chief-clancy 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +13 -24
  2. package/dist/bundle/clancy-afk.js +101 -0
  3. package/dist/bundle/clancy-once.js +13902 -0
  4. package/dist/installer/file-ops/file-ops.d.ts +32 -0
  5. package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
  6. package/dist/installer/file-ops/file-ops.js +58 -0
  7. package/dist/installer/file-ops/file-ops.js.map +1 -0
  8. package/dist/installer/hook-installer/hook-installer.d.ts +29 -0
  9. package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
  10. package/dist/installer/hook-installer/hook-installer.js +96 -0
  11. package/dist/installer/hook-installer/hook-installer.js.map +1 -0
  12. package/dist/installer/install.d.ts +3 -0
  13. package/dist/installer/install.d.ts.map +1 -0
  14. package/dist/installer/install.js +248 -0
  15. package/dist/installer/install.js.map +1 -0
  16. package/dist/installer/manifest/manifest.d.ts +41 -0
  17. package/dist/installer/manifest/manifest.d.ts.map +1 -0
  18. package/dist/installer/manifest/manifest.js +97 -0
  19. package/dist/installer/manifest/manifest.js.map +1 -0
  20. package/dist/installer/prompts/prompts.d.ts +33 -0
  21. package/dist/installer/prompts/prompts.d.ts.map +1 -0
  22. package/dist/installer/prompts/prompts.js +55 -0
  23. package/dist/installer/prompts/prompts.js.map +1 -0
  24. package/dist/schemas/env.d.ts +75 -0
  25. package/dist/schemas/env.d.ts.map +1 -0
  26. package/dist/schemas/env.js +40 -0
  27. package/dist/schemas/env.js.map +1 -0
  28. package/dist/schemas/github.d.ts +27 -0
  29. package/dist/schemas/github.d.ts.map +1 -0
  30. package/dist/schemas/github.js +17 -0
  31. package/dist/schemas/github.js.map +1 -0
  32. package/dist/schemas/index.d.ts +9 -0
  33. package/dist/schemas/index.d.ts.map +1 -0
  34. package/dist/schemas/index.js +5 -0
  35. package/dist/schemas/index.js.map +1 -0
  36. package/dist/schemas/jira.d.ts +37 -0
  37. package/dist/schemas/jira.d.ts.map +1 -0
  38. package/dist/schemas/jira.js +37 -0
  39. package/dist/schemas/jira.js.map +1 -0
  40. package/dist/schemas/linear.d.ts +67 -0
  41. package/dist/schemas/linear.d.ts.map +1 -0
  42. package/dist/schemas/linear.js +50 -0
  43. package/dist/schemas/linear.js.map +1 -0
  44. package/dist/scripts/afk/afk.d.ts +21 -0
  45. package/dist/scripts/afk/afk.d.ts.map +1 -0
  46. package/dist/scripts/afk/afk.js +124 -0
  47. package/dist/scripts/afk/afk.js.map +1 -0
  48. package/dist/scripts/board/github/github.d.ts +40 -0
  49. package/dist/scripts/board/github/github.d.ts.map +1 -0
  50. package/dist/scripts/board/github/github.js +121 -0
  51. package/dist/scripts/board/github/github.js.map +1 -0
  52. package/dist/scripts/board/jira/jira.d.ts +90 -0
  53. package/dist/scripts/board/jira/jira.d.ts.map +1 -0
  54. package/dist/scripts/board/jira/jira.js +251 -0
  55. package/dist/scripts/board/jira/jira.js.map +1 -0
  56. package/dist/scripts/board/linear/linear.d.ts +85 -0
  57. package/dist/scripts/board/linear/linear.d.ts.map +1 -0
  58. package/dist/scripts/board/linear/linear.js +209 -0
  59. package/dist/scripts/board/linear/linear.js.map +1 -0
  60. package/dist/scripts/once/once.d.ts +12 -0
  61. package/dist/scripts/once/once.d.ts.map +1 -0
  62. package/dist/scripts/once/once.js +330 -0
  63. package/dist/scripts/once/once.js.map +1 -0
  64. package/dist/scripts/shared/branch/branch.d.ts +50 -0
  65. package/dist/scripts/shared/branch/branch.d.ts.map +1 -0
  66. package/dist/scripts/shared/branch/branch.js +61 -0
  67. package/dist/scripts/shared/branch/branch.js.map +1 -0
  68. package/dist/scripts/shared/claude-cli/claude-cli.d.ts +17 -0
  69. package/dist/scripts/shared/claude-cli/claude-cli.d.ts.map +1 -0
  70. package/dist/scripts/shared/claude-cli/claude-cli.js +35 -0
  71. package/dist/scripts/shared/claude-cli/claude-cli.js.map +1 -0
  72. package/dist/scripts/shared/env-parser/env-parser.d.ts +30 -0
  73. package/dist/scripts/shared/env-parser/env-parser.d.ts.map +1 -0
  74. package/dist/scripts/shared/env-parser/env-parser.js +64 -0
  75. package/dist/scripts/shared/env-parser/env-parser.js.map +1 -0
  76. package/dist/scripts/shared/env-schema/env-schema.d.ts +27 -0
  77. package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -0
  78. package/dist/scripts/shared/env-schema/env-schema.js +46 -0
  79. package/dist/scripts/shared/env-schema/env-schema.js.map +1 -0
  80. package/dist/scripts/shared/git-ops/git-ops.d.ts +52 -0
  81. package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -0
  82. package/dist/scripts/shared/git-ops/git-ops.js +107 -0
  83. package/dist/scripts/shared/git-ops/git-ops.js.map +1 -0
  84. package/dist/scripts/shared/http/http.d.ts +52 -0
  85. package/dist/scripts/shared/http/http.d.ts.map +1 -0
  86. package/dist/scripts/shared/http/http.js +74 -0
  87. package/dist/scripts/shared/http/http.js.map +1 -0
  88. package/dist/scripts/shared/notify/notify.d.ts +46 -0
  89. package/dist/scripts/shared/notify/notify.d.ts.map +1 -0
  90. package/dist/scripts/shared/notify/notify.js +88 -0
  91. package/dist/scripts/shared/notify/notify.js.map +1 -0
  92. package/dist/scripts/shared/preflight/preflight.d.ts +40 -0
  93. package/dist/scripts/shared/preflight/preflight.d.ts.map +1 -0
  94. package/dist/scripts/shared/preflight/preflight.js +84 -0
  95. package/dist/scripts/shared/preflight/preflight.js.map +1 -0
  96. package/dist/scripts/shared/progress/progress.d.ts +25 -0
  97. package/dist/scripts/shared/progress/progress.d.ts.map +1 -0
  98. package/dist/scripts/shared/progress/progress.js +46 -0
  99. package/dist/scripts/shared/progress/progress.js.map +1 -0
  100. package/dist/scripts/shared/prompt/prompt.d.ts +38 -0
  101. package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -0
  102. package/dist/scripts/shared/prompt/prompt.js +77 -0
  103. package/dist/scripts/shared/prompt/prompt.js.map +1 -0
  104. package/dist/types/board.d.ts +13 -0
  105. package/dist/types/board.d.ts.map +1 -0
  106. package/dist/types/board.js +5 -0
  107. package/dist/types/board.js.map +1 -0
  108. package/dist/types/index.d.ts +3 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/index.js +2 -0
  111. package/dist/types/index.js.map +1 -0
  112. package/dist/utils/ansi/ansi.d.ts +55 -0
  113. package/dist/utils/ansi/ansi.d.ts.map +1 -0
  114. package/dist/utils/ansi/ansi.js +55 -0
  115. package/dist/utils/ansi/ansi.js.map +1 -0
  116. package/dist/utils/parse-json/parse-json.d.ts +20 -0
  117. package/dist/utils/parse-json/parse-json.d.ts.map +1 -0
  118. package/dist/utils/parse-json/parse-json.js +27 -0
  119. package/dist/utils/parse-json/parse-json.js.map +1 -0
  120. package/hooks/clancy-check-update.js +2 -2
  121. package/hooks/clancy-credential-guard.js +8 -1
  122. package/package.json +48 -8
  123. package/registry/boards.json +3 -6
  124. package/src/templates/CLAUDE.md +1 -1
  125. package/src/workflows/doctor.md +32 -23
  126. package/src/workflows/init.md +101 -26
  127. package/src/workflows/logs.md +13 -6
  128. package/src/workflows/map-codebase.md +17 -16
  129. package/src/workflows/once.md +22 -12
  130. package/src/workflows/review.md +40 -27
  131. package/src/workflows/run.md +20 -12
  132. package/src/workflows/scaffold.md +5 -1034
  133. package/src/workflows/settings.md +9 -6
  134. package/src/workflows/status.md +17 -8
  135. package/src/workflows/uninstall.md +11 -6
  136. package/src/workflows/update.md +20 -13
  137. package/bin/install.js +0 -362
  138. package/src/templates/scripts/clancy-afk.sh +0 -111
  139. package/src/templates/scripts/clancy-once-github.sh +0 -249
  140. package/src/templates/scripts/clancy-once-linear.sh +0 -320
  141. package/src/templates/scripts/clancy-once.sh +0 -322
@@ -1,111 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Strict mode: exit on error (-e), undefined variables (-u), pipe failures (-o pipefail).
3
- # This means any command that fails will stop the script immediately rather than silently continuing.
4
- set -euo pipefail
5
-
6
- # ─── WHAT THIS SCRIPT DOES ─────────────────────────────────────────────────────
7
- #
8
- # Loop runner for Clancy. Calls clancy-once.sh repeatedly until:
9
- # - No more tickets are found ("No tickets found", "All done", etc.)
10
- # - A preflight check fails (output line starting with ✗)
11
- # - MAX_ITERATIONS is reached
12
- # - The user presses Ctrl+C
13
- #
14
- # This script does not know about boards. All board logic lives in clancy-once.sh,
15
- # which is always the runtime filename regardless of which board is configured.
16
- # /clancy:init copies the correct board variant as clancy-once.sh during setup.
17
- #
18
- # ───────────────────────────────────────────────────────────────────────────────
19
-
20
- # ─── PREFLIGHT ─────────────────────────────────────────────────────────────────
21
-
22
- command -v claude >/dev/null 2>&1 || {
23
- echo "✗ claude CLI not found."
24
- echo " Install it: https://claude.ai/code"
25
- exit 0
26
- }
27
- command -v jq >/dev/null 2>&1 || {
28
- echo "✗ jq not found."
29
- echo " Install: brew install jq (mac) | apt install jq (linux)"
30
- exit 0
31
- }
32
- command -v curl >/dev/null 2>&1 || {
33
- echo "✗ curl not found. Install curl for your OS."
34
- exit 0
35
- }
36
-
37
- [ -f .clancy/.env ] || {
38
- echo "✗ .clancy/.env not found."
39
- echo " Copy .clancy/.env.example to .clancy/.env and fill in your credentials."
40
- exit 0
41
- }
42
- # shellcheck source=/dev/null
43
- source .clancy/.env
44
-
45
- git rev-parse --git-dir >/dev/null 2>&1 || {
46
- echo "✗ Not a git repository."
47
- echo " Clancy must be run from the root of a git project."
48
- exit 0
49
- }
50
-
51
- # ─── END PREFLIGHT ─────────────────────────────────────────────────────────────
52
-
53
- MAX_ITERATIONS=${MAX_ITERATIONS:-5}
54
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55
-
56
- # clancy-once.sh is always the runtime filename regardless of board.
57
- # /clancy:init copies the correct board variant as clancy-once.sh.
58
- ONCE_SCRIPT="$SCRIPT_DIR/clancy-once.sh"
59
-
60
- if [ ! -f "$ONCE_SCRIPT" ]; then
61
- echo "✗ Script not found: $ONCE_SCRIPT"
62
- echo " Run /clancy:init to scaffold scripts."
63
- exit 0
64
- fi
65
-
66
- echo "Starting Clancy — will process up to $MAX_ITERATIONS ticket(s). Ctrl+C to stop early."
67
- echo ""
68
-
69
- i=0
70
- while [ "$i" -lt "$MAX_ITERATIONS" ]; do
71
- i=$((i + 1))
72
- echo ""
73
- echo "=== Iteration $i of $MAX_ITERATIONS ==="
74
-
75
- # Run clancy-once.sh and stream its output live via tee.
76
- # tee writes to both stdout (visible to user) and a temp file (for stop-condition checks).
77
- # Without tee, output would be buffered in a variable and hidden during implementation.
78
- TMPFILE=$(mktemp)
79
- bash "$ONCE_SCRIPT" 2>&1 | tee "$TMPFILE"
80
- OUTPUT=$(cat "$TMPFILE")
81
- rm -f "$TMPFILE"
82
-
83
- # Stop if no tickets remain
84
- if echo "$OUTPUT" | grep -qE "No tickets found|No issues found|All done"; then
85
- echo ""
86
- echo "✓ Clancy finished — no more tickets."
87
- exit 0
88
- fi
89
-
90
- # Stop if Claude skipped the ticket (not implementable from the codebase).
91
- # Re-running would just fetch and skip the same ticket again — stop and let
92
- # the user update the ticket or remove it from the queue before continuing.
93
- if echo "$OUTPUT" | grep -q "Ticket skipped"; then
94
- echo ""
95
- echo "⚠ Clancy stopped — ticket was skipped (not implementable from the codebase)."
96
- echo " Update the ticket to focus on codebase work, then re-run."
97
- exit 0
98
- fi
99
-
100
- # Stop if a preflight check failed (lines starting with ✗)
101
- if echo "$OUTPUT" | grep -qE "^✗ "; then
102
- echo ""
103
- echo "✗ Clancy stopped — preflight check failed. See output above."
104
- exit 0
105
- fi
106
-
107
- sleep 2
108
- done
109
-
110
- echo ""
111
- echo "Reached max iterations ($MAX_ITERATIONS). Run clancy-afk.sh again to continue."
@@ -1,249 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Strict mode: exit on error (-e), undefined variables (-u), pipe failures (-o pipefail).
3
- # This means any command that fails will stop the script immediately rather than silently continuing.
4
- set -euo pipefail
5
-
6
- # Parse flags — must happen before preflight so --dry-run works without side effects.
7
- DRY_RUN=false
8
- for arg in "$@"; do
9
- case "$arg" in
10
- --dry-run) DRY_RUN=true ;;
11
- esac
12
- done
13
- readonly DRY_RUN
14
-
15
- # ─── WHAT THIS SCRIPT DOES ─────────────────────────────────────────────────────
16
- #
17
- # Board: GitHub Issues
18
- #
19
- # 1. Preflight — checks all required tools, credentials, and repo reachability
20
- # 2. Fetch — pulls the next open issue with the 'clancy' label assigned to you
21
- # 3. Branch — creates a feature branch from the issue's milestone branch (or base branch)
22
- # 4. Implement — passes the issue to Claude Code, which reads .clancy/docs/ and implements it
23
- # 5. Merge — squash-merges the feature branch back into the target branch
24
- # 6. Close — marks the GitHub issue as closed via the API
25
- # 7. Log — appends a completion entry to .clancy/progress.txt
26
- #
27
- # This script is run once per issue. The loop is handled by clancy-afk.sh.
28
- #
29
- # NOTE: GitHub's /issues endpoint returns pull requests too. This script filters
30
- # them out by checking for the presence of the 'pull_request' key in each result.
31
- #
32
- # NOTE: Failures use exit 0, not exit 1. This is intentional — clancy-afk.sh
33
- # detects stop conditions by reading script output rather than exit codes, so a
34
- # non-zero exit would be treated as an unexpected crash rather than a clean stop.
35
- #
36
- # ───────────────────────────────────────────────────────────────────────────────
37
-
38
- # ─── PREFLIGHT ─────────────────────────────────────────────────────────────────
39
-
40
- command -v claude >/dev/null 2>&1 || {
41
- echo "✗ claude CLI not found."
42
- echo " Install it: https://claude.ai/code"
43
- exit 0
44
- }
45
- command -v jq >/dev/null 2>&1 || {
46
- echo "✗ jq not found."
47
- echo " Install: brew install jq (mac) | apt install jq (linux)"
48
- exit 0
49
- }
50
- command -v curl >/dev/null 2>&1 || {
51
- echo "✗ curl not found. Install curl for your OS."
52
- exit 0
53
- }
54
-
55
- [ -f .clancy/.env ] || {
56
- echo "✗ .clancy/.env not found."
57
- echo " Copy .clancy/.env.example to .clancy/.env and fill in your credentials."
58
- echo " Then run: /clancy:init"
59
- exit 0
60
- }
61
- # shellcheck source=/dev/null
62
- source .clancy/.env
63
-
64
- git rev-parse --git-dir >/dev/null 2>&1 || {
65
- echo "✗ Not a git repository."
66
- echo " Clancy must be run from the root of a git project."
67
- exit 0
68
- }
69
-
70
- if ! git diff --quiet || ! git diff --cached --quiet; then
71
- echo "⚠ Working directory has uncommitted changes."
72
- echo " Consider stashing or committing first to avoid confusion."
73
- fi
74
-
75
- [ -n "${GITHUB_TOKEN:-}" ] || { echo "✗ GITHUB_TOKEN is not set in .clancy/.env"; exit 0; }
76
- [ -n "${GITHUB_REPO:-}" ] || { echo "✗ GITHUB_REPO is not set in .clancy/.env"; exit 0; }
77
-
78
- # Validate GITHUB_REPO format — must be owner/repo with safe characters only
79
- if ! echo "$GITHUB_REPO" | grep -qE '^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$'; then
80
- echo "✗ GITHUB_REPO format is invalid. Expected owner/repo (e.g. acme/my-app). Check GITHUB_REPO in .clancy/.env."
81
- exit 0
82
- fi
83
-
84
- PING=$(curl -s -o /dev/null -w "%{http_code}" \
85
- -H "Authorization: Bearer $GITHUB_TOKEN" \
86
- -H "X-GitHub-Api-Version: 2022-11-28" \
87
- "https://api.github.com/repos/$GITHUB_REPO")
88
-
89
- case "$PING" in
90
- 200) ;;
91
- 401) echo "✗ GitHub authentication failed. Check GITHUB_TOKEN in .clancy/.env."; exit 0 ;;
92
- 403) echo "✗ GitHub access denied. Your token may lack the repo scope."; exit 0 ;;
93
- 404) echo "✗ GitHub repo '$GITHUB_REPO' not found. Check GITHUB_REPO in .clancy/.env."; exit 0 ;;
94
- 000) echo "✗ Could not reach GitHub. Check your network."; exit 0 ;;
95
- *) echo "✗ GitHub returned unexpected status $PING. Check your config."; exit 0 ;;
96
- esac
97
-
98
- if [ "${PLAYWRIGHT_ENABLED:-}" = "true" ]; then
99
- if lsof -ti:"${PLAYWRIGHT_DEV_PORT:-5173}" >/dev/null 2>&1; then
100
- echo "⚠ Port ${PLAYWRIGHT_DEV_PORT:-5173} is already in use."
101
- echo " If visual checks fail, stop whatever is using the port first."
102
- fi
103
- fi
104
-
105
- echo "✓ Preflight passed. Starting Clancy..."
106
-
107
- # ─── END PREFLIGHT ─────────────────────────────────────────────────────────────
108
-
109
- # ─── FETCH ISSUE ───────────────────────────────────────────────────────────────
110
-
111
- # Fetch open issues assigned to the authenticated user with the 'clancy' label.
112
- # GitHub's issues endpoint returns PRs too — filter them out by checking for pull_request key.
113
- # per_page=3 so we can find one real issue even if the first result(s) are PRs.
114
- RESPONSE=$(curl -s \
115
- -H "Authorization: Bearer $GITHUB_TOKEN" \
116
- -H "X-GitHub-Api-Version: 2022-11-28" \
117
- "https://api.github.com/repos/$GITHUB_REPO/issues?state=open&assignee=@me&labels=clancy&per_page=3")
118
-
119
- # Verify response is an array before parsing (guards against error objects on rate limit / transient failure)
120
- if ! echo "$RESPONSE" | jq -e 'type == "array"' >/dev/null 2>&1; then
121
- ERR_MSG=$(echo "$RESPONSE" | jq -r '.message // "Unexpected response"' 2>/dev/null || echo "Unexpected response")
122
- echo "✗ GitHub API error: $ERR_MSG. Check GITHUB_TOKEN in .clancy/.env."
123
- exit 0
124
- fi
125
-
126
- # Filter out PRs and take first real issue
127
- ISSUE=$(echo "$RESPONSE" | jq 'map(select(has("pull_request") | not)) | .[0]')
128
-
129
- if [ "$(echo "$ISSUE" | jq 'type')" = '"null"' ] || [ -z "$(echo "$ISSUE" | jq -r '.number // empty')" ]; then
130
- echo "No issues found. All done!"
131
- exit 0
132
- fi
133
-
134
- ISSUE_NUMBER=$(echo "$ISSUE" | jq -r '.number')
135
- TITLE=$(echo "$ISSUE" | jq -r '.title')
136
- BODY=$(echo "$ISSUE" | jq -r '.body // "No description"')
137
- MILESTONE=$(echo "$ISSUE" | jq -r '.milestone.title // "none"')
138
-
139
- BASE_BRANCH="${CLANCY_BASE_BRANCH:-main}"
140
- TICKET_BRANCH="feature/issue-${ISSUE_NUMBER}"
141
-
142
- # GitHub has no native epic concept — use milestone as the grouping signal.
143
- # If the issue has a milestone, branch from milestone/{slug} (creating it from
144
- # BASE_BRANCH if it doesn't exist yet). Otherwise branch from BASE_BRANCH directly.
145
- if [ "$MILESTONE" != "none" ]; then
146
- MILESTONE_SLUG=$(echo "$MILESTONE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd '[:alnum:]-')
147
- TARGET_BRANCH="milestone/${MILESTONE_SLUG}"
148
- else
149
- TARGET_BRANCH="$BASE_BRANCH"
150
- fi
151
-
152
- # ─── DRY RUN ───────────────────────────────────────────────────────────────────
153
-
154
- if [ "$DRY_RUN" = "true" ]; then
155
- echo ""
156
- echo "── Dry run ──────────────────────────────────────"
157
- echo " Issue: [#${ISSUE_NUMBER}] $TITLE"
158
- echo " Milestone: $MILESTONE"
159
- echo " Target branch: $TARGET_BRANCH"
160
- echo " Feature branch: $TICKET_BRANCH"
161
- echo "─────────────────────────────────────────────────"
162
- echo " No changes made. Remove --dry-run to run for real."
163
- exit 0
164
- fi
165
-
166
- # ─── IMPLEMENT ─────────────────────────────────────────────────────────────────
167
-
168
- echo "Picking up: [#${ISSUE_NUMBER}] $TITLE"
169
- echo "Milestone: $MILESTONE | Target branch: $TARGET_BRANCH"
170
-
171
- git show-ref --verify --quiet "refs/heads/$TARGET_BRANCH" \
172
- || git checkout -b "$TARGET_BRANCH" "$BASE_BRANCH"
173
- git checkout "$TARGET_BRANCH"
174
- # -B creates the branch if it doesn't exist, or resets it to HEAD if it does.
175
- # This handles retries cleanly without failing on an already-existing branch.
176
- git checkout -B "$TICKET_BRANCH"
177
-
178
- PROMPT="You are implementing GitHub Issue #${ISSUE_NUMBER}.
179
-
180
- Title: $TITLE
181
- Milestone: $MILESTONE
182
-
183
- Description:
184
- $BODY
185
-
186
- Step 0 — Executability check (do this before any git or file operation):
187
- Read the issue title and description above. Can this issue be implemented entirely
188
- as a code change committed to this repo? Consult the 'Executability check' section of
189
- CLAUDE.md for the full list of skip conditions.
190
-
191
- If you must SKIP this issue:
192
- 1. Output: ⚠ Skipping [#${ISSUE_NUMBER}]: {one-line reason}
193
- 2. Output: Ticket skipped — update it to be codebase-only work, then re-run.
194
- 3. Append to .clancy/progress.txt: YYYY-MM-DD HH:MM | #${ISSUE_NUMBER} | SKIPPED | {reason}
195
- 4. Stop — no branches, no file changes, no git operations.
196
-
197
- If the issue IS implementable, continue:
198
- 1. Read core docs in .clancy/docs/: STACK.md, ARCHITECTURE.md, CONVENTIONS.md, GIT.md, DEFINITION-OF-DONE.md, CONCERNS.md
199
- Also read if relevant to this ticket: INTEGRATIONS.md (external APIs/services/auth), TESTING.md (tests/specs/coverage), DESIGN-SYSTEM.md (UI/components/styles), ACCESSIBILITY.md (accessibility/ARIA/WCAG)
200
- 2. Follow the conventions in GIT.md exactly
201
- 3. Implement the issue fully
202
- 4. Commit your work following the conventions in GIT.md
203
- 5. When done, confirm you are finished."
204
-
205
- CLAUDE_ARGS=(--dangerously-skip-permissions)
206
- [ -n "${CLANCY_MODEL:-}" ] && CLAUDE_ARGS+=(--model "$CLANCY_MODEL")
207
- echo "$PROMPT" | claude "${CLAUDE_ARGS[@]}"
208
-
209
- # ─── MERGE, CLOSE & LOG ────────────────────────────────────────────────────────
210
-
211
- # Squash all commits from the feature branch into a single commit on the target branch.
212
- git checkout "$TARGET_BRANCH"
213
- git merge --squash "$TICKET_BRANCH"
214
- if git diff --cached --quiet; then
215
- echo "⚠ No changes staged after squash merge. Claude may not have committed any work."
216
- else
217
- git commit -m "feat(#${ISSUE_NUMBER}): $TITLE"
218
- fi
219
-
220
- # Delete ticket branch locally
221
- git branch -d "$TICKET_BRANCH"
222
-
223
- # Close the issue — warn but don't fail if this doesn't go through
224
- CLOSE_HTTP=$(curl -s -o /dev/null -w "%{http_code}" -X PATCH \
225
- -H "Authorization: Bearer $GITHUB_TOKEN" \
226
- -H "X-GitHub-Api-Version: 2022-11-28" \
227
- -H "Content-Type: application/json" \
228
- "https://api.github.com/repos/$GITHUB_REPO/issues/${ISSUE_NUMBER}" \
229
- -d '{"state": "closed"}')
230
- [ "$CLOSE_HTTP" = "200" ] || echo "⚠ Could not close issue #${ISSUE_NUMBER} (HTTP $CLOSE_HTTP). Close it manually on GitHub."
231
-
232
- # Log progress
233
- echo "$(date '+%Y-%m-%d %H:%M') | #${ISSUE_NUMBER} | $TITLE | DONE" >> .clancy/progress.txt
234
-
235
- echo "✓ #${ISSUE_NUMBER} complete."
236
-
237
- # Send completion notification if webhook is configured
238
- if [ -n "${CLANCY_NOTIFY_WEBHOOK:-}" ]; then
239
- NOTIFY_MSG="✓ Clancy completed [#${ISSUE_NUMBER}] $TITLE"
240
- if echo "$CLANCY_NOTIFY_WEBHOOK" | grep -q "hooks.slack.com"; then
241
- curl -s -X POST "$CLANCY_NOTIFY_WEBHOOK" \
242
- -H "Content-Type: application/json" \
243
- -d "$(jq -n --arg text "$NOTIFY_MSG" '{"text": $text}')" >/dev/null 2>&1 || true
244
- else
245
- curl -s -X POST "$CLANCY_NOTIFY_WEBHOOK" \
246
- -H "Content-Type: application/json" \
247
- -d "$(jq -n --arg text "$NOTIFY_MSG" '{"type":"message","attachments":[{"contentType":"application/vnd.microsoft.card.adaptive","content":{"type":"AdaptiveCard","body":[{"type":"TextBlock","text":$text}]}}]}')" >/dev/null 2>&1 || true
248
- fi
249
- fi