@jenga-ai/agent 1.0.0

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 (177) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +340 -0
  3. package/agents/ai_engineer.md +113 -0
  4. package/agents/developer.md +236 -0
  5. package/agents/scrum-master.md +349 -0
  6. package/agents/scrutiny-agent.md +137 -0
  7. package/agents/solution-assessor.md +185 -0
  8. package/agents/tester.md +339 -0
  9. package/bin/jenga.js +70 -0
  10. package/hooks/copilot_session_end.sh +29 -0
  11. package/hooks/on_session_end.sh +238 -0
  12. package/hooks/prompt_router.sh +11 -0
  13. package/hooks/prompt_router_helper.js +52 -0
  14. package/hooks/session_end_helper.js +29 -0
  15. package/hooks/session_end_watcher.sh +24 -0
  16. package/lib/commands/attach.js +47 -0
  17. package/lib/commands/init.js +207 -0
  18. package/lib/commands/start.js +16 -0
  19. package/lib/commands/status.js +53 -0
  20. package/lib/config-schema.js +72 -0
  21. package/lib/inject-settings.js +61 -0
  22. package/lib/mirror.js +244 -0
  23. package/lib/resolve-project-dir.sh +47 -0
  24. package/mcp/execute-ticket/index.js +10 -0
  25. package/mcp/execute-ticket/package.json +5 -0
  26. package/mcp/help/index.js +79 -0
  27. package/mcp/help/package.json +14 -0
  28. package/mcp/router/README.md +19 -0
  29. package/mcp/router/embedder.js +23 -0
  30. package/mcp/router/index.js +204 -0
  31. package/mcp/router/matcher.js +87 -0
  32. package/mcp/router/package-lock.json +1048 -0
  33. package/mcp/router/package.json +11 -0
  34. package/mcp/router/skill-index.js +104 -0
  35. package/package.json +47 -0
  36. package/scripts/board_resolver.sh +46 -0
  37. package/scripts/e25_s01_extract_board_graph.py +292 -0
  38. package/scripts/e25_s01_generate_synthetic_board.py +90 -0
  39. package/scripts/measurement-10x.json +50 -0
  40. package/scripts/measurement-10x.txt +4 -0
  41. package/scripts/measurement-real.json +50 -0
  42. package/scripts/measurement-real.txt +4 -0
  43. package/scripts/postinstall.js +165 -0
  44. package/scripts/todo_cleanup.sh +22 -0
  45. package/scripts/todo_manager.sh +86 -0
  46. package/scripts/validate-board.sh +190 -0
  47. package/scripts/validate-story-format.sh +53 -0
  48. package/skills/brainstorm/SKILL.md +47 -0
  49. package/skills/btw/SKILL.md +42 -0
  50. package/skills/commit/SKILL.md +29 -0
  51. package/skills/commit/assets/user_instructions_template.md +22 -0
  52. package/skills/continue/SKILL.md +29 -0
  53. package/skills/convert/SKILL.md +124 -0
  54. package/skills/convert/convert_cli.py +235 -0
  55. package/skills/convert/tests/sample.csv +4 -0
  56. package/skills/convert/tests/sample.json +5 -0
  57. package/skills/convert/tests/sample.jsonl +3 -0
  58. package/skills/convert/tests/sample.yaml +18 -0
  59. package/skills/convert/tests/sample_obj.csv +2 -0
  60. package/skills/convert/tests/sample_obj.json +9 -0
  61. package/skills/deep-dive/SKILL.md +167 -0
  62. package/skills/do/SKILL.md +88 -0
  63. package/skills/do/assets/sender_template.json +12 -0
  64. package/skills/doc/SKILL.md +314 -0
  65. package/skills/doc/assets/path-objectives.yaml +38 -0
  66. package/skills/doc-sync/SKILL.md +167 -0
  67. package/skills/doc-sync/assets/default_excludes.txt +21 -0
  68. package/skills/doc-sync/assets/doc_targets.md +14 -0
  69. package/skills/dooo/SKILL.md +60 -0
  70. package/skills/error/SKILL.md +29 -0
  71. package/skills/evaluate/SKILL.md +45 -0
  72. package/skills/evaluate/assets/evaluation_invokation_template.yml +3 -0
  73. package/skills/evaluate/assets/evaluation_rapport_template.md +24 -0
  74. package/skills/examplify/SKILL.md +42 -0
  75. package/skills/help/SKILL.md +36 -0
  76. package/skills/improve/SKILL.md +55 -0
  77. package/skills/index/scripts/board-index +4 -0
  78. package/skills/index/scripts/board_index.py +615 -0
  79. package/skills/index/scripts/smoke_test.sh +86 -0
  80. package/skills/init/SKILL.md +44 -0
  81. package/skills/init/assets/.gitignore_template +15 -0
  82. package/skills/init/assets/PROJECT_SUMMARY_template.md +13 -0
  83. package/skills/init/assets/directory_structure.txt +13 -0
  84. package/skills/init/assets/test-config_template.json +4 -0
  85. package/skills/init/assets/workflow_template.json +30 -0
  86. package/skills/init/scripts/init.sh +48 -0
  87. package/skills/jbp/SKILL.md +25 -0
  88. package/skills/jenga/SKILL.md +68 -0
  89. package/skills/lgtm/SKILL.md +21 -0
  90. package/skills/mirror-public/SKILL.md +237 -0
  91. package/skills/mirror-public/assets/config.json +5 -0
  92. package/skills/mirror-public/scripts/mirror.sh +374 -0
  93. package/skills/pi-plan/SKILL.md +62 -0
  94. package/skills/pi-plan/assets/epic.json +7 -0
  95. package/skills/pi-plan/assets/story_template.md +18 -0
  96. package/skills/proceed/SKILL.md +29 -0
  97. package/skills/publish/SKILL.md +351 -0
  98. package/skills/publish/adapters/droplet.md +200 -0
  99. package/skills/publish/adapters/mobile-ios.md +114 -0
  100. package/skills/publish/adapters/npm-ci.md +223 -0
  101. package/skills/publish/adapters/npm.md +121 -0
  102. package/skills/publish/assets/ExportOptions.plist.template +19 -0
  103. package/skills/publish/assets/ci-contract.md +111 -0
  104. package/skills/publish/assets/ownership-matrix.md +17 -0
  105. package/skills/publish/assets/publish.example.json +85 -0
  106. package/skills/publish/assets/publish.example.npm-ci.json +40 -0
  107. package/skills/publish/assets/publish.example.npm.json +41 -0
  108. package/skills/publish/assets/secrets-guide.md +104 -0
  109. package/skills/publish/schemas/fixtures/npm-ci-minimal.json +17 -0
  110. package/skills/publish/schemas/fixtures/npm-ci-with-empty-secrets.json +18 -0
  111. package/skills/publish/schemas/fixtures/npm-ci-with-workflow-path.json +18 -0
  112. package/skills/publish/schemas/publish.schema.json +428 -0
  113. package/skills/publish/scripts/check_target_config.sh +96 -0
  114. package/skills/publish/scripts/droplet_pipeline.sh +208 -0
  115. package/skills/publish/scripts/generate_release_notes.sh +200 -0
  116. package/skills/publish/scripts/ios_pipeline.sh +486 -0
  117. package/skills/publish/scripts/npm_ci_pipeline.sh +225 -0
  118. package/skills/publish/scripts/npm_pipeline.sh +249 -0
  119. package/skills/publish/scripts/publish_common.sh +253 -0
  120. package/skills/publish/scripts/publish_deploy.sh +538 -0
  121. package/skills/publish/scripts/reconcile_tags.sh +135 -0
  122. package/skills/publish/scripts/run_gates.sh +616 -0
  123. package/skills/publish/scripts/setup_wizard.sh +394 -0
  124. package/skills/publish/scripts/show_history.sh +95 -0
  125. package/skills/publish/scripts/suggest_semver_bump.sh +105 -0
  126. package/skills/publish/scripts/validate_config.sh +163 -0
  127. package/skills/publish/scripts/validate_droplet_env.sh +45 -0
  128. package/skills/publish/scripts/validate_ios_env.sh +68 -0
  129. package/skills/publish/scripts/validate_npm_ci_env.sh +71 -0
  130. package/skills/publish/scripts/validate_npm_env.sh +22 -0
  131. package/skills/publish/scripts/write_ledger_entry.sh +126 -0
  132. package/skills/publish/wizards/droplet.md +275 -0
  133. package/skills/publish/wizards/mobile-ios.md +157 -0
  134. package/skills/publish/wizards/npm-ci.md +240 -0
  135. package/skills/publish/wizards/npm.md +224 -0
  136. package/skills/reconcile/SKILL.md +93 -0
  137. package/skills/reconcile/assets/report_format.md +44 -0
  138. package/skills/reconcile-origin/SKILL.md +75 -0
  139. package/skills/reconcile-origin/scripts/reconcile-origin.sh +372 -0
  140. package/skills/redo/SKILL.md +70 -0
  141. package/skills/route/SKILL.md +180 -0
  142. package/skills/self-sync/SKILL.md +73 -0
  143. package/skills/self-sync/scripts/run.js +136 -0
  144. package/skills/skillify/SKILL.md +68 -0
  145. package/skills/skillify/assets/init-new/SKILL.md +35 -0
  146. package/skills/skillify/assets/init-new/assets/.gitignore_template +15 -0
  147. package/skills/skillify/assets/init-new/assets/PROJECT_SUMMARY_template.md +13 -0
  148. package/skills/skillify/assets/init-new/assets/directory_structure.txt +10 -0
  149. package/skills/skillify/assets/init-new/assets/test-config_template.json +4 -0
  150. package/skills/skillify/assets/init-new/assets/workflow_template.json +17 -0
  151. package/skills/skillify/assets/init-new/scripts/init.sh +48 -0
  152. package/skills/skillify/assets/init-old/SKILL.md +124 -0
  153. package/skills/spinoff/SKILL.md +48 -0
  154. package/skills/status/SKILL.md +33 -0
  155. package/skills/status/assets/output_format.md +41 -0
  156. package/skills/todo/SKILL.md +46 -0
  157. package/skills/todo/assets/todo_handoff_template.md +22 -0
  158. package/skills/todo/assets/todo_template.md +3 -0
  159. package/skills/train/SKILL.md +116 -0
  160. package/skills/train/assets/dashboard-templates/classifiers.html +106 -0
  161. package/skills/train/assets/dashboard-templates/nlp.html +102 -0
  162. package/skills/train/assets/dashboard-templates/transformers.html +98 -0
  163. package/skills/train/assets/results-parsers/__init__.py +9 -0
  164. package/skills/train/assets/results-parsers/classifiers.py +84 -0
  165. package/skills/train/assets/results-parsers/nlp.py +88 -0
  166. package/skills/train/assets/results-parsers/reporter.py +154 -0
  167. package/skills/train/assets/results-parsers/transformers.py +120 -0
  168. package/skills/train/train_cli.py +786 -0
  169. package/templates/EXECUTION_PLAN_TEMPLATE.md +43 -0
  170. package/templates/EXECUTION_SUMMARY_TEMPLATE.md +50 -0
  171. package/templates/JENGA_CONFIG_TEMPLATE.json +23 -0
  172. package/templates/PROBLEM_RAPPORT_TEMPLATE.md +88 -0
  173. package/templates/SCRUM_BOARD_SCHEMA.md +311 -0
  174. package/templates/SKILL.md +16 -0
  175. package/templates/SKILL_TEMPLATE.md +28 -0
  176. package/templates/USER_INSTRUCTIONS_TEMPLATE.md +22 -0
  177. package/templates/copilot-instructions.md.tpl +55 -0
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ emit_error() {
5
+ local branch="${1:-}"
6
+ local code="$2"
7
+ local message="$3"
8
+ python3 - "$branch" "$code" "$message" <<'PY'
9
+ import json
10
+ import sys
11
+
12
+ branch, code, message = sys.argv[1:4]
13
+ payload = {
14
+ "status": "error",
15
+ "code": code,
16
+ "message": message,
17
+ }
18
+ if branch:
19
+ payload["branch"] = branch
20
+ print(json.dumps(payload, ensure_ascii=False))
21
+ PY
22
+ }
23
+
24
+ emit_local_branch_missing() {
25
+ local branch="$1"
26
+ local remote_exists="$2"
27
+ python3 - "$branch" "$remote_exists" <<'PY'
28
+ import json
29
+ import sys
30
+
31
+ branch = sys.argv[1]
32
+ remote_exists = sys.argv[2].lower() == "true"
33
+ print(json.dumps({
34
+ "status": "local_branch_missing",
35
+ "branch": branch,
36
+ "remote_exists": remote_exists,
37
+ "message": "The requested branch does not exist locally."
38
+ }, ensure_ascii=False))
39
+ PY
40
+ }
41
+
42
+ emit_ok() {
43
+ local branch="$1"
44
+ local rebased_commits="$2"
45
+ python3 - "$branch" "$rebased_commits" <<'PY'
46
+ import json
47
+ import sys
48
+
49
+ branch, rebased_commits = sys.argv[1], int(sys.argv[2])
50
+ print(json.dumps({
51
+ "status": "ok",
52
+ "branch": branch,
53
+ "rebased_commits": rebased_commits,
54
+ }, ensure_ascii=False))
55
+ PY
56
+ }
57
+
58
+ emit_handled_later() {
59
+ local file="$1"
60
+ python3 - "$file" <<'PY'
61
+ import json
62
+ import sys
63
+
64
+ print(json.dumps({
65
+ "status": "handled_later",
66
+ "file": sys.argv[1],
67
+ }, ensure_ascii=False))
68
+ PY
69
+ }
70
+
71
+ rebase_in_progress() {
72
+ local git_dir
73
+ git_dir="$(git rev-parse --git-dir)"
74
+ [[ -d "$git_dir/rebase-merge" || -d "$git_dir/rebase-apply" ]]
75
+ }
76
+
77
+ annotate_conflicts() {
78
+ local file="$1"
79
+ local branch="$2"
80
+ python3 - "$file" "$branch" <<'PY'
81
+ from pathlib import Path
82
+ import sys
83
+
84
+ path = Path(sys.argv[1])
85
+ branch = sys.argv[2]
86
+ lines = path.read_text(encoding="utf-8").splitlines(keepends=True)
87
+ comment_block = [
88
+ "# RECONCILE-ORIGIN CONFLICT:\n",
89
+ f"# Local commits and origin/{branch} both changed the lines below in {path}.\n",
90
+ "# Resolve the conflict when you are ready, then remove this note if it is no longer needed.\n",
91
+ ]
92
+
93
+ result = []
94
+ i = 0
95
+ while i < len(lines):
96
+ line = lines[i]
97
+ if line.startswith("<<<<<<< "):
98
+ if len(result) >= len(comment_block) and result[-len(comment_block):] == comment_block:
99
+ pass
100
+ else:
101
+ result.extend(comment_block)
102
+ result.append(line)
103
+ i += 1
104
+
105
+ path.write_text("".join(result), encoding="utf-8")
106
+ PY
107
+ }
108
+
109
+ build_conflict_report() {
110
+ local branch="$1"
111
+ shift
112
+ python3 - "$branch" "$@" <<'PY'
113
+ import json
114
+ import sys
115
+ from pathlib import Path
116
+
117
+ branch = sys.argv[1]
118
+ files = sys.argv[2:]
119
+ conflicts = []
120
+
121
+ for file_path in files:
122
+ path = Path(file_path)
123
+ if not path.exists():
124
+ continue
125
+
126
+ lines = path.read_text(encoding="utf-8").splitlines()
127
+ blocks = []
128
+ i = 0
129
+ while i < len(lines):
130
+ line = lines[i]
131
+ if line.startswith("<<<<<<< "):
132
+ i += 1
133
+ origin_lines = []
134
+ while i < len(lines) and lines[i] != "=======":
135
+ origin_lines.append(lines[i])
136
+ i += 1
137
+ if i < len(lines) and lines[i] == "=======":
138
+ i += 1
139
+ local_lines = []
140
+ while i < len(lines) and not lines[i].startswith(">>>>>>>"):
141
+ local_lines.append(lines[i])
142
+ i += 1
143
+ while i < len(lines) and not lines[i].startswith(">>>>>>>"):
144
+ i += 1
145
+ if i < len(lines) and lines[i].startswith(">>>>>>>"):
146
+ i += 1
147
+ blocks.append(("\n".join(local_lines).strip(), "\n".join(origin_lines).strip()))
148
+ else:
149
+ i += 1
150
+
151
+ if not blocks:
152
+ continue
153
+
154
+ local_text = "\n\n---\n\n".join(block[0] for block in blocks)
155
+ origin_text = "\n\n---\n\n".join(block[1] for block in blocks)
156
+ conflicts.append({
157
+ "file": file_path,
158
+ "local_section": local_text,
159
+ "origin_section": origin_text,
160
+ "description": f"Overlapping edits between local commits and origin/{branch} across {len(blocks)} conflict block(s).",
161
+ })
162
+
163
+ print(json.dumps({
164
+ "status": "conflict",
165
+ "branch": branch,
166
+ "conflicts": conflicts,
167
+ }, ensure_ascii=False))
168
+ PY
169
+ }
170
+
171
+ fetch_origin_branch() {
172
+ local branch="$1"
173
+ git fetch origin "refs/heads/$branch:refs/remotes/origin/$branch" >/dev/null 2>&1
174
+ }
175
+
176
+ ensure_clean_worktree() {
177
+ if [[ -n "$(git status --porcelain)" ]]; then
178
+ emit_error "$1" "uncommitted_changes" "Uncommitted changes detected. Stash or commit them before reconciling with origin."
179
+ exit 1
180
+ fi
181
+ }
182
+
183
+ ensure_branch_context() {
184
+ local branch="$1"
185
+ local create_tracking="$2"
186
+ local current_branch
187
+ current_branch="$(git branch --show-current)"
188
+
189
+ if ! git show-ref --verify --quiet "refs/heads/$branch"; then
190
+ if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
191
+ if [[ "$create_tracking" == "true" ]]; then
192
+ fetch_origin_branch "$branch" || {
193
+ emit_error "$branch" "branch_not_found_on_origin" "Unable to fetch origin/$branch."
194
+ exit 1
195
+ }
196
+ git checkout -b "$branch" --track "origin/$branch" >/dev/null 2>&1 || {
197
+ emit_error "$branch" "checkout_failed" "Unable to create and check out local tracking branch $branch."
198
+ exit 1
199
+ }
200
+ else
201
+ emit_local_branch_missing "$branch" "true"
202
+ exit 0
203
+ fi
204
+ else
205
+ emit_local_branch_missing "$branch" "false"
206
+ exit 0
207
+ fi
208
+ elif [[ "$current_branch" != "$branch" ]]; then
209
+ git checkout "$branch" >/dev/null 2>&1 || {
210
+ emit_error "$branch" "checkout_failed" "Unable to check out local branch $branch."
211
+ exit 1
212
+ }
213
+ fi
214
+ }
215
+
216
+ run_standard_reconcile() {
217
+ local branch="$1"
218
+ fetch_origin_branch "$branch" || {
219
+ emit_error "$branch" "branch_not_found_on_origin" "Branch origin/$branch was not found or could not be fetched."
220
+ exit 1
221
+ }
222
+
223
+ local rebased_commits
224
+ rebased_commits="$(git rev-list --count "origin/$branch..HEAD" 2>/dev/null || echo 0)"
225
+
226
+ if git rebase "origin/$branch" >/dev/null 2>&1; then
227
+ emit_ok "$branch" "$rebased_commits"
228
+ return 0
229
+ fi
230
+
231
+ local conflict_files
232
+ conflict_files="$(git diff --name-only --diff-filter=U || true)"
233
+ if [[ -n "$conflict_files" ]]; then
234
+ local -a conflict_array=()
235
+ while IFS= read -r line; do
236
+ [[ -n "$line" ]] && conflict_array+=("$line")
237
+ done <<<"$conflict_files"
238
+ local report
239
+ report="$(build_conflict_report "$branch" "${conflict_array[@]}")"
240
+ git rebase --abort >/dev/null 2>&1 || true
241
+ printf '%s\n' "$report"
242
+ return 0
243
+ fi
244
+
245
+ if rebase_in_progress; then
246
+ git rebase --abort >/dev/null 2>&1 || true
247
+ fi
248
+ emit_error "$branch" "rebase_failed" "The rebase failed before conflict details could be collected."
249
+ exit 1
250
+ }
251
+
252
+ run_handle_later() {
253
+ local branch="$1"
254
+ local target_file="$2"
255
+
256
+ fetch_origin_branch "$branch" || {
257
+ emit_error "$branch" "branch_not_found_on_origin" "Branch origin/$branch was not found or could not be fetched."
258
+ exit 1
259
+ }
260
+
261
+ local rebased_commits
262
+ rebased_commits="$(git rev-list --count "origin/$branch..HEAD" 2>/dev/null || echo 0)"
263
+
264
+ if git rebase "origin/$branch" >/dev/null 2>&1; then
265
+ emit_ok "$branch" "$rebased_commits"
266
+ return 0
267
+ fi
268
+
269
+ local conflict_files
270
+ conflict_files="$(git diff --name-only --diff-filter=U || true)"
271
+ if [[ -z "$conflict_files" ]]; then
272
+ if rebase_in_progress; then
273
+ git rebase --abort >/dev/null 2>&1 || true
274
+ fi
275
+ emit_error "$branch" "rebase_failed" "The rebase failed before the requested conflict could be handled."
276
+ exit 1
277
+ fi
278
+
279
+ if ! printf '%s\n' "$conflict_files" | grep -Fxq "$target_file"; then
280
+ local -a conflict_array=()
281
+ while IFS= read -r line; do
282
+ [[ -n "$line" ]] && conflict_array+=("$line")
283
+ done <<<"$conflict_files"
284
+ local report
285
+ report="$(build_conflict_report "$branch" "${conflict_array[@]}")"
286
+ git rebase --abort >/dev/null 2>&1 || true
287
+ printf '%s\n' "$report"
288
+ exit 1
289
+ fi
290
+
291
+ while true; do
292
+ annotate_conflicts "$target_file" "$branch"
293
+ git add "$target_file"
294
+
295
+ if GIT_EDITOR=true git rebase --continue >/dev/null 2>&1; then
296
+ emit_handled_later "$target_file"
297
+ return 0
298
+ fi
299
+
300
+ conflict_files="$(git diff --name-only --diff-filter=U || true)"
301
+ if [[ -z "$conflict_files" ]]; then
302
+ emit_error "$branch" "rebase_continue_failed" "Rebase continuation failed after annotating $target_file."
303
+ exit 1
304
+ fi
305
+
306
+ if printf '%s\n' "$conflict_files" | grep -Fxq "$target_file"; then
307
+ continue
308
+ fi
309
+
310
+ emit_handled_later "$target_file"
311
+ return 0
312
+ done
313
+ }
314
+
315
+ branch_arg=""
316
+ handle_later_file=""
317
+ create_tracking="false"
318
+
319
+ while [[ $# -gt 0 ]]; do
320
+ case "$1" in
321
+ --handle-later)
322
+ shift
323
+ if [[ $# -eq 0 ]]; then
324
+ emit_error "$branch_arg" "missing_handle_later_file" "The --handle-later flag requires a file path."
325
+ exit 1
326
+ fi
327
+ handle_later_file="$1"
328
+ ;;
329
+ --create-tracking)
330
+ create_tracking="true"
331
+ ;;
332
+ -h|--help)
333
+ cat <<'USAGE'
334
+ Usage: reconcile-origin.sh [<branch>] [--handle-later <file>] [--create-tracking]
335
+ USAGE
336
+ exit 0
337
+ ;;
338
+ *)
339
+ if [[ -n "$branch_arg" ]]; then
340
+ emit_error "$branch_arg" "unexpected_argument" "Unexpected argument: $1"
341
+ exit 1
342
+ fi
343
+ branch_arg="$1"
344
+ ;;
345
+ esac
346
+ shift
347
+ done
348
+
349
+ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
350
+ emit_error "$branch_arg" "not_a_git_repository" "This command must be run inside a git work tree."
351
+ exit 1
352
+ fi
353
+
354
+ if rebase_in_progress; then
355
+ emit_error "$branch_arg" "rebase_in_progress" "A rebase is already in progress. Resolve or abort it before running reconcile-origin."
356
+ exit 1
357
+ fi
358
+
359
+ branch="${branch_arg:-$(git branch --show-current)}"
360
+ if [[ -z "$branch" ]]; then
361
+ emit_error "$branch" "detached_head" "Unable to determine the current branch from a detached HEAD state."
362
+ exit 1
363
+ fi
364
+
365
+ ensure_clean_worktree "$branch"
366
+ ensure_branch_context "$branch" "$create_tracking"
367
+
368
+ if [[ -n "$handle_later_file" ]]; then
369
+ run_handle_later "$branch" "$handle_later_file"
370
+ else
371
+ run_standard_reconcile "$branch"
372
+ fi
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: redo
3
+ description: Redo parts or entire previous implementations identified by a commit SHA or an Epic/Story number (e.g. E01, E02_S03). Expects an identifier and a description of what to redo and why. Use when the user wants to revisit, rework, or rewrite previously completed work, including updating all affected documentation.
4
+ keywords:
5
+ - redo
6
+ - rework
7
+ - rewrite
8
+ - revisit
9
+ - redo task
10
+ examples:
11
+ - "redo the login implementation"
12
+ - "rewrite story E02_S01"
13
+ metadata:
14
+ prefered_agent: scrum-master
15
+ ---
16
+
17
+ # Redo — Rework a Previous Implementation
18
+
19
+ ## Input Format
20
+
21
+ ```
22
+ /redo <identifier> <description>
23
+ ```
24
+
25
+ - **identifier** — One of:
26
+ - A git commit SHA (full or short, e.g. `a1b2c3f`)
27
+ - An Epic number (e.g. `E01`)
28
+ - A Story number (e.g. `E02_S03`)
29
+ - **description** — What should be redone and, if relevant, why, how, or to what end.
30
+
31
+ If either part is missing, ask the user to provide it before proceeding.
32
+
33
+ ## Instructions
34
+
35
+ ### 1. Resolve the identifier
36
+ **Commit SHA:**
37
+ - Run `git --no-pager log --stat -1 <SHA>` to retrieve the commit message and changed files.
38
+ - Run `git --no-pager show <SHA>` to inspect the full diff.
39
+
40
+ **Epic / Story number:**
41
+ - Read the matching file under `$(bash scripts/board_resolver.sh)epics/` or `$(bash scripts/board_resolver.sh)stories/` to understand the scope.
42
+ - Use `git --no-pager log --all --oneline --grep="<epic or story title>"` to locate related commits and their diffs.
43
+
44
+ Collect the list of **files originally changed** and the **original intent** of the implementation.
45
+
46
+ ### 2. Assess scope
47
+ Compare the user's redo description against the original implementation to determine:
48
+ - Which files need to change.
49
+ - Whether the redo is a partial revision (some files/logic) or a full rewrite.
50
+ - Which tests cover the affected code.
51
+ - Which documentation files reference the affected code or feature (check `project/`, `documentation/`, `project/documentation/`, `README.md`, `WARP.md`).
52
+
53
+ Summarise scope findings to the user in a brief list before continuing.
54
+
55
+ ### 3. Plan the redo
56
+ Populate `skills/todo/assets/todo_handoff_template.md` with the following pre-collected context:
57
+ - **Mission title**: a short name for the redo work
58
+ - **Goal / objective**: the redo objective — what is changing and the desired outcome
59
+ - **Affected files or scope**: code, tests, and documentation files identified in step 2
60
+ - **Intended approach**: step-by-step changes
61
+ - **Epic/Story linkage**: the identifier resolved in step 1 (e.g. `E02_S03`), or `None` if a commit SHA
62
+
63
+ Then invoke the `/todo` skill with the populated template. Since the template fields are pre-filled, `/todo` should skip any questions already answered.
64
+
65
+ Wait for user approval before executing unless the user explicitly told you to go ahead.
66
+
67
+ ## Examples
68
+ - `/redo a1b2c3f Rewrite the auth middleware to use JWT instead of session tokens`
69
+ - `/redo E02_S03 Replace the REST endpoints with GraphQL — the client team needs a flexible query interface`
70
+ - `/redo E01 Redo the entire onboarding epic using the new design-system components`
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: route
3
+ description: Intelligently routes a prompt to the best-matching skill in the project. Reads available skills, matches the input semantically and by keyword, enriches the prompt with board context and documentation references, then invokes the matched skill with the full context prepended.
4
+ keywords:
5
+ - "route"
6
+ - "dispatch"
7
+ - "auto skill"
8
+ - "smart prompt"
9
+ - "find skill"
10
+ examples:
11
+ - "route: I want to plan a new feature"
12
+ - "route: something is broken in the auth module"
13
+ - "route: let's review what's done so far"
14
+ - "route: analyze this approach in depth before we commit"
15
+ - "route: add a task to capture this idea"
16
+ ---
17
+
18
+ # Route — Intelligent Skill Dispatcher
19
+
20
+ ## Purpose
21
+
22
+ `/route <prompt>` takes any natural-language input, finds the best-matching skill in the project, enriches it with live board context and documentation references, and invokes the matched skill — all in a single, fully-loaded message.
23
+
24
+ ---
25
+
26
+ ## Instructions
27
+
28
+ ### Step 1 — Discover Available Skills
29
+
30
+ Scan both skill registries (they may differ slightly — check both):
31
+
32
+ ```
33
+ .agents/skills/<name>/SKILL.md
34
+ .claude/skills/<name>/SKILL.md (if the directory exists)
35
+ skills/<name>/SKILL.md (if the directory exists)
36
+ ```
37
+
38
+ For each skill found, extract the following fields from its YAML front-matter:
39
+
40
+ | Field | Purpose |
41
+ |---|---|
42
+ | `name` | Canonical identifier |
43
+ | `description` | Primary match signal |
44
+ | `keywords` | Exact/partial keyword match |
45
+ | `examples` | Semantic match reference |
46
+ | `metadata.prefered_agent` | Which agent to delegate to |
47
+
48
+ Build an in-memory skill registry from this data before proceeding.
49
+
50
+ ---
51
+
52
+ ### Step 2 — Match the Prompt to a Skill
53
+
54
+ Run matching in three passes (stop at first confident match):
55
+
56
+ #### Pass 1 — Keyword Match
57
+ Check whether any phrase from a skill's `keywords` list appears verbatim (case-insensitive) in the prompt.
58
+
59
+ #### Pass 2 — Example Similarity
60
+ Compare the prompt against each skill's `examples` list. Treat this as a semantic similarity check: pick the skill whose examples most closely reflect the intent of the prompt.
61
+
62
+ #### Pass 3 — Description Match
63
+ If no clear winner has emerged, compare the prompt against each skill's `description` field. Pick the skill whose description best captures what the user is trying to do.
64
+
65
+ **If two or more skills score equally**, present the top candidates and ask the user to choose:
66
+
67
+ ```
68
+ More than one skill matches your prompt. Which should I apply?
69
+ 1. /<skill-a> — <one-line description>
70
+ 2. /<skill-b> — <one-line description>
71
+ 3. Neither — describe what you need
72
+ ```
73
+
74
+ **If no skill matches at all**, inform the user and offer:
75
+
76
+ ```
77
+ No matching skill found for: "<prompt>"
78
+ Would you like to:
79
+ 1. Browse all available skills (/help)
80
+ 2. Create a new skill for this use case (/btw)
81
+ 3. Proceed without a skill (raw prompt)
82
+ ```
83
+
84
+ ---
85
+
86
+ ### Step 3 — Check the Board for Related Context
87
+
88
+ Read `project/configs/workflow.json` for board paths (default: `project/board/`).
89
+
90
+ Scan the board for items that are topically related to the prompt:
91
+
92
+ 1. **Epics** — `project/board/epics/` — check `title` and `description` fields
93
+ 2. **Stories** — `project/board/stories/` — check `title` and `description` fields
94
+ 3. **Tasks** — `project/board/tasks/` — check `title` and `description` fields
95
+
96
+ Extract any items whose title or description contains keywords from the prompt. Limit to the **top 5 most relevant** results. Do not include items whose status is `Archived` or `Cancelled`.
97
+
98
+ ---
99
+
100
+ ### Step 4 — Check Documentation
101
+
102
+ Scan the following directories for relevant documentation files:
103
+
104
+ ```
105
+ project/documentation/plans/
106
+ project/documentation/summaries/
107
+ project/documentation/examples/
108
+ docs/
109
+ ```
110
+
111
+ Match filenames and headings against the prompt keywords. Collect the **top 3 most relevant** file paths.
112
+
113
+ ---
114
+
115
+ ### Step 5 — Construct the Enriched Prompt
116
+
117
+ Assemble the following composite message in **exactly this order**:
118
+
119
+ #### Part A — Matched Skill (full content)
120
+ Inline the **full body** of the matched skill's `SKILL.md` (everything after the YAML front-matter). This is placed first so the agent reads the skill instructions before anything else.
121
+
122
+ ```
123
+ <!-- SKILL: /<matched-skill-name> -->
124
+ <full skill instructions>
125
+ <!-- END SKILL -->
126
+ ```
127
+
128
+ #### Part B — Board & Documentation Context
129
+ Immediately after the skill, append a context block:
130
+
131
+ ```markdown
132
+ ---
133
+ ## 📋 Relevant Board Context
134
+
135
+ <list each matched board item as:>
136
+ - [<status>] **<ID>** — <title> (`project/board/<type>/<filename>`)
137
+
138
+ ## 📄 Relevant Documentation
139
+
140
+ <list each matched doc as:>
141
+ - `<file-path>` — <one-line summary of the doc's purpose>
142
+ ---
143
+ ```
144
+
145
+ If no board items or docs were found, omit the corresponding section rather than leaving it empty.
146
+
147
+ #### Part C — Original Prompt
148
+ Finally, append the user's original unmodified prompt:
149
+
150
+ ```
151
+ ## 🗣 Original Prompt
152
+
153
+ > <original prompt verbatim>
154
+ ```
155
+
156
+ ---
157
+
158
+ ### Step 6 — Invoke the Matched Skill
159
+
160
+ Deliver the enriched composite message to the appropriate agent:
161
+
162
+ - If the matched skill specifies `metadata.prefered_agent`, load that agent's definition from `agents/<prefered_agent>.md` and pass the full composite message to it.
163
+ - If no `prefered_agent` is specified, execute the skill instructions directly using the composite message as the working input.
164
+
165
+ Do **not** summarise or restate the composite message — deliver it as-is.
166
+
167
+ ---
168
+
169
+ ### Step 7 — Report Routing Decision
170
+
171
+ Before invoking the skill, briefly inform the user:
172
+
173
+ ```
174
+ Routing to: /<matched-skill-name>
175
+ Reason: <one sentence explaining why this skill was chosen>
176
+ Board items found: <count>
177
+ Docs found: <count>
178
+ ```
179
+
180
+ Then proceed immediately — do not wait for user confirmation unless the match was ambiguous (Step 2 tie-break already handled that).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: self-sync
3
+ description: Mirror this repo's root-level framework directories into its own `.claude/` and `.agents/` sub-trees so edits to `/skills/*`, `/agents/*`, `/hooks/*`, `/scripts/*`, `/templates/*`, and `settings.json` take effect in the current Claude Code (and non-Claude) agent session — the in-repo replacement for the retired `/distribute` self-sync loop.
4
+ keywords:
5
+ - "self sync"
6
+ - "mirror skills"
7
+ - "sync .claude"
8
+ - "sync .agents"
9
+ - "in-repo distribute"
10
+ examples:
11
+ - "self-sync the mirrors"
12
+ - "/self-sync --dry-run"
13
+ - "refresh .claude/skills from root"
14
+ ---
15
+
16
+ # Self-Sync
17
+
18
+ Copies the framework's root-level entries into this repo's own `.claude/` and `.agents/` mirrors so agent tooling (Claude Code, Copilot, custom) picks up local edits without reinstalling or running `/distribute`.
19
+
20
+ Delegates the actual filesystem work to `lib/mirror.js`, the same helper used by `scripts/postinstall.js` on consumer installs. Two-directory mirror + delete reconciliation are the only differences from that consumer path.
21
+
22
+ ## Instructions
23
+
24
+ 1. If the user passed `--dry-run` (or asked for a preview), invoke:
25
+ ```
26
+ node skills/self-sync/scripts/run.js --dry-run
27
+ ```
28
+ Report the printed plan (added / overwritten / deleted) verbatim.
29
+
30
+ 2. Otherwise, invoke:
31
+ ```
32
+ node skills/self-sync/scripts/run.js
33
+ ```
34
+ Report the printed summary. Do not run any inline `cp`, `rsync`, or `fs` commands — all mirroring goes through the script.
35
+
36
+ 3. If the summary shows `+0 ~0 -0` on a second consecutive real run, the mirrors are already in sync — surface that as confirmation of idempotency.
37
+
38
+ ## Copy Set
39
+
40
+ The script mirrors exactly these root-level entries:
41
+
42
+ ```
43
+ bin/ lib/ scripts/ agents/ hooks/ mcp/ skills/ templates/ settings.json
44
+ ```
45
+
46
+ This is an **explicit constant** in `scripts/run.js`, deliberately not derived at runtime from `package.json` `files`. Two reasons:
47
+
48
+ - `package.json` `files` includes `README.md` and `LICENSE`, which should not appear in the agent mirrors.
49
+ - `settings.json` is required in the mirrors but is intentionally not shipped in the npm tarball, so it does not appear in `files`.
50
+
51
+ The list is kept aligned with `package.json` `files` by convention. If a new top-level framework directory is added, update both.
52
+
53
+ ## Invocation Model
54
+
55
+ **Manual invocation only.** The user runs `/self-sync` (or `node skills/self-sync/scripts/run.js`) after making framework edits and before expecting them to be visible to the current agent session.
56
+
57
+ Rationale: an on-`/commit` or file-watch trigger would fire on every edit — including drafts that shouldn't leak into the mirrors — and would obscure the write footprint (delete reconciliation prunes orphans, so accidental deletes on the source side propagate). Making the sync explicit keeps the human in the loop for a destructive-by-default operation, which matches the framework's boundary-checked, dry-runnable posture.
58
+
59
+ ## Dry-Run Behavior
60
+
61
+ `--dry-run` computes the full plan (added / overwritten / deleted / unchanged) via `lib/mirror.js` without touching the filesystem. Use it before every real run when the mirror state is uncertain, or when running in a repo where uncommitted mirror edits might exist.
62
+
63
+ ## Safety Guarantees
64
+
65
+ - **Never writes outside the repo root.** `lib/mirror.js` boundary-checks every destination path with `assertInside(destRoot, target)`; the helper throws if a resolved child escapes its destination root.
66
+ - **Additive helper + explicit reconciliation.** The mirror helper is additive by default; delete reconciliation is enabled only because this skill passes `reconcileDeletes: true`.
67
+ - **No shell out.** Pure Node built-ins (`node:fs`, `node:path`) — no `cp`, `rsync`, or subprocess calls.
68
+ - **Idempotent.** A second consecutive run reports `+0 ~0 -0` because the byte-comparison in `filesEqual` classifies unchanged files as `skipped`.
69
+
70
+ ## Guard Rails
71
+
72
+ - Do not inline mirroring logic in this skill body — all filesystem work goes through `scripts/run.js` → `lib/mirror.js`.
73
+ - Do not run this skill from a directory other than a checkout of the framework repo itself. `scripts/postinstall.js` handles consumer installs; this skill handles the framework's own repo.