@aperant/framework 0.6.3 → 0.6.5

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 (244) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +64 -10
  3. package/agents/apt-improver.md +99 -0
  4. package/agents/apt-planner.md +115 -10
  5. package/dist/__test-helpers/run-cmd.d.mts +4 -2
  6. package/dist/__test-helpers/run-cmd.d.mts.map +1 -1
  7. package/dist/__test-helpers/run-cmd.mjs +56 -15
  8. package/dist/__test-helpers/run-cmd.mjs.map +1 -1
  9. package/dist/cli/artifacts/classification.d.mts.map +1 -1
  10. package/dist/cli/artifacts/classification.mjs +10 -0
  11. package/dist/cli/artifacts/classification.mjs.map +1 -1
  12. package/dist/cli/ci-watch/lock.d.mts +53 -0
  13. package/dist/cli/ci-watch/lock.d.mts.map +1 -0
  14. package/dist/cli/ci-watch/lock.mjs +172 -0
  15. package/dist/cli/ci-watch/lock.mjs.map +1 -0
  16. package/dist/cli/ci-watch/state.d.mts +36 -0
  17. package/dist/cli/ci-watch/state.d.mts.map +1 -0
  18. package/dist/cli/ci-watch/state.mjs +103 -0
  19. package/dist/cli/ci-watch/state.mjs.map +1 -0
  20. package/dist/cli/ci-watch/stop-matrix.d.mts +58 -0
  21. package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -0
  22. package/dist/cli/ci-watch/stop-matrix.mjs +164 -0
  23. package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -0
  24. package/dist/cli/cli-wrappers/ci-watch.d.mts +2 -0
  25. package/dist/cli/cli-wrappers/ci-watch.d.mts.map +1 -0
  26. package/dist/cli/cli-wrappers/ci-watch.mjs +9 -0
  27. package/dist/cli/cli-wrappers/ci-watch.mjs.map +1 -0
  28. package/dist/cli/commands/adr.d.mts +5 -0
  29. package/dist/cli/commands/adr.d.mts.map +1 -0
  30. package/dist/cli/commands/adr.mjs +228 -0
  31. package/dist/cli/commands/adr.mjs.map +1 -0
  32. package/dist/cli/commands/ci-watch.d.mts +7 -0
  33. package/dist/cli/commands/ci-watch.d.mts.map +1 -0
  34. package/dist/cli/commands/ci-watch.mjs +465 -0
  35. package/dist/cli/commands/ci-watch.mjs.map +1 -0
  36. package/dist/cli/commands/context.d.mts +7 -0
  37. package/dist/cli/commands/context.d.mts.map +1 -0
  38. package/dist/cli/commands/context.mjs +224 -0
  39. package/dist/cli/commands/context.mjs.map +1 -0
  40. package/dist/cli/commands/event.d.mts.map +1 -1
  41. package/dist/cli/commands/event.mjs +59 -24
  42. package/dist/cli/commands/event.mjs.map +1 -1
  43. package/dist/cli/commands/host-detect.d.mts +1 -1
  44. package/dist/cli/commands/host-detect.d.mts.map +1 -1
  45. package/dist/cli/commands/host-detect.mjs +30 -3
  46. package/dist/cli/commands/host-detect.mjs.map +1 -1
  47. package/dist/cli/commands/init.d.mts.map +1 -1
  48. package/dist/cli/commands/init.mjs +73 -5
  49. package/dist/cli/commands/init.mjs.map +1 -1
  50. package/dist/cli/commands/modes.d.mts +13 -0
  51. package/dist/cli/commands/modes.d.mts.map +1 -0
  52. package/dist/cli/commands/modes.mjs +220 -0
  53. package/dist/cli/commands/modes.mjs.map +1 -0
  54. package/dist/cli/commands/pr-review-audit-fixer.d.mts +41 -2
  55. package/dist/cli/commands/pr-review-audit-fixer.d.mts.map +1 -1
  56. package/dist/cli/commands/pr-review-audit-fixer.mjs +91 -14
  57. package/dist/cli/commands/pr-review-audit-fixer.mjs.map +1 -1
  58. package/dist/cli/commands/route.d.mts.map +1 -1
  59. package/dist/cli/commands/route.mjs +11 -2
  60. package/dist/cli/commands/route.mjs.map +1 -1
  61. package/dist/cli/commands/task.d.mts.map +1 -1
  62. package/dist/cli/commands/task.mjs +136 -6
  63. package/dist/cli/commands/task.mjs.map +1 -1
  64. package/dist/cli/commands/tokens.d.mts.map +1 -1
  65. package/dist/cli/commands/tokens.mjs +150 -6
  66. package/dist/cli/commands/tokens.mjs.map +1 -1
  67. package/dist/cli/commands/triage.d.mts +8 -0
  68. package/dist/cli/commands/triage.d.mts.map +1 -0
  69. package/dist/cli/commands/triage.mjs +259 -0
  70. package/dist/cli/commands/triage.mjs.map +1 -0
  71. package/dist/cli/config/post-merge-sweep.d.mts +18 -0
  72. package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
  73. package/dist/cli/config/post-merge-sweep.mjs +48 -3
  74. package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
  75. package/dist/cli/consistency/registry.d.mts +11 -0
  76. package/dist/cli/consistency/registry.d.mts.map +1 -1
  77. package/dist/cli/consistency/registry.mjs +13 -0
  78. package/dist/cli/consistency/registry.mjs.map +1 -1
  79. package/dist/cli/coordination/agent-identity.d.mts +9 -0
  80. package/dist/cli/coordination/agent-identity.d.mts.map +1 -1
  81. package/dist/cli/coordination/agent-identity.mjs +11 -0
  82. package/dist/cli/coordination/agent-identity.mjs.map +1 -1
  83. package/dist/cli/coordination/event-log.d.mts +27 -0
  84. package/dist/cli/coordination/event-log.d.mts.map +1 -1
  85. package/dist/cli/coordination/event-log.mjs +72 -2
  86. package/dist/cli/coordination/event-log.mjs.map +1 -1
  87. package/dist/cli/design/frontmatter-schema.d.mts +3 -3
  88. package/dist/cli/design/frontmatter-schema.d.mts.map +1 -1
  89. package/dist/cli/design/frontmatter-schema.mjs +3 -1
  90. package/dist/cli/design/frontmatter-schema.mjs.map +1 -1
  91. package/dist/cli/dispatch.d.mts.map +1 -1
  92. package/dist/cli/dispatch.mjs +14 -1
  93. package/dist/cli/dispatch.mjs.map +1 -1
  94. package/dist/cli/gate/registry.d.mts +11 -0
  95. package/dist/cli/gate/registry.d.mts.map +1 -1
  96. package/dist/cli/gate/registry.mjs +13 -0
  97. package/dist/cli/gate/registry.mjs.map +1 -1
  98. package/dist/cli/help.d.mts.map +1 -1
  99. package/dist/cli/help.mjs +1 -0
  100. package/dist/cli/help.mjs.map +1 -1
  101. package/dist/cli/host/detect.d.mts +1 -0
  102. package/dist/cli/host/detect.d.mts.map +1 -1
  103. package/dist/cli/host/detect.mjs +5 -0
  104. package/dist/cli/host/detect.mjs.map +1 -1
  105. package/dist/cli/route/envelope.d.mts +68 -4
  106. package/dist/cli/route/envelope.d.mts.map +1 -1
  107. package/dist/cli/route/envelope.mjs +140 -103
  108. package/dist/cli/route/envelope.mjs.map +1 -1
  109. package/dist/cli/route/skill-discover.d.mts +11 -0
  110. package/dist/cli/route/skill-discover.d.mts.map +1 -1
  111. package/dist/cli/route/skill-discover.mjs +46 -1
  112. package/dist/cli/route/skill-discover.mjs.map +1 -1
  113. package/dist/cli/skill-author/contract.d.mts +20 -0
  114. package/dist/cli/skill-author/contract.d.mts.map +1 -1
  115. package/dist/cli/skill-author/contract.mjs +27 -0
  116. package/dist/cli/skill-author/contract.mjs.map +1 -1
  117. package/dist/cli/skill-author/skill-template.d.mts.map +1 -1
  118. package/dist/cli/skill-author/skill-template.mjs +4 -3
  119. package/dist/cli/skill-author/skill-template.mjs.map +1 -1
  120. package/dist/cli/task/worktree-cleanup.d.mts +9 -1
  121. package/dist/cli/task/worktree-cleanup.d.mts.map +1 -1
  122. package/dist/cli/task/worktree-cleanup.mjs +190 -9
  123. package/dist/cli/task/worktree-cleanup.mjs.map +1 -1
  124. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  125. package/dist/plugin/agents/apt-planner.md +1 -1
  126. package/dist/plugin/skills/apt/SKILL.md +111 -5
  127. package/dist/plugin/skills/apt-author-skill/SKILL.md +11 -0
  128. package/dist/plugin/skills/apt-bootstrap/SKILL.md +1 -0
  129. package/dist/plugin/skills/apt-classify/SKILL.md +1 -0
  130. package/dist/plugin/skills/apt-close-task/SKILL.md +1 -0
  131. package/dist/plugin/skills/apt-create-docs/SKILL.md +1 -0
  132. package/dist/plugin/skills/apt-debug/SKILL.md +2 -0
  133. package/dist/plugin/skills/apt-design/SKILL.md +2 -0
  134. package/dist/plugin/skills/apt-discuss/SKILL.md +2 -0
  135. package/dist/plugin/skills/apt-docs/SKILL.md +2 -0
  136. package/dist/plugin/skills/apt-execute/SKILL.md +1 -0
  137. package/dist/plugin/skills/apt-mockup/SKILL.md +2 -0
  138. package/dist/plugin/skills/apt-pause/SKILL.md +1 -0
  139. package/dist/plugin/skills/apt-personas/SKILL.md +1 -0
  140. package/dist/plugin/skills/apt-plan/SKILL.md +2 -0
  141. package/dist/plugin/skills/apt-pr-review/SKILL.md +1 -0
  142. package/dist/plugin/skills/apt-quick/SKILL.md +2 -0
  143. package/dist/plugin/skills/apt-resume/SKILL.md +1 -0
  144. package/dist/plugin/skills/apt-review/SKILL.md +1 -0
  145. package/dist/plugin/skills/apt-roadmap/SKILL.md +1 -0
  146. package/dist/plugin/skills/apt-roundtable/SKILL.md +2 -0
  147. package/dist/plugin/skills/apt-run/SKILL.md +1 -0
  148. package/dist/plugin/skills/apt-scan/SKILL.md +1 -0
  149. package/dist/plugin/skills/apt-setup/SKILL.md +1 -0
  150. package/dist/plugin/skills/apt-ship/SKILL.md +6 -5
  151. package/dist/plugin/skills/apt-stress-test/SKILL.md +1 -0
  152. package/dist/plugin/skills/apt-terminal/SKILL.md +1 -0
  153. package/dist/plugin/skills/apt-update/SKILL.md +5 -0
  154. package/dist/plugin/skills/apt-verify/SKILL.md +1 -0
  155. package/dist/plugin/skills/apt-verify-proof/SKILL.md +1 -0
  156. package/dist/types/config.d.ts +85 -0
  157. package/dist/types/config.d.ts.map +1 -1
  158. package/package.json +125 -122
  159. package/prompts/coder.md +2 -0
  160. package/prompts/planner.md +12 -0
  161. package/prompts/spec_writer.md +9 -0
  162. package/skills/apt/SKILL.md +112 -5
  163. package/skills/apt-author-skill/SKILL.md +11 -0
  164. package/skills/apt-bootstrap/SKILL.md +1 -0
  165. package/skills/apt-classify/SKILL.md +1 -0
  166. package/skills/apt-close-task/SKILL.md +33 -1
  167. package/skills/apt-create-docs/SKILL.md +1 -0
  168. package/skills/apt-debug/SKILL.md +41 -6
  169. package/skills/apt-debug/appendices/diagnose-discipline.md +119 -0
  170. package/skills/apt-design/SKILL.md +2 -0
  171. package/skills/apt-diagram/SKILL.md +342 -0
  172. package/skills/apt-diagram/appendices/design-discipline.md +97 -0
  173. package/skills/apt-discuss/SKILL.md +27 -0
  174. package/skills/apt-discuss/appendices/grill-discipline.md +104 -0
  175. package/skills/apt-discuss/appendices/zoom-out-helper.md +79 -0
  176. package/skills/apt-docs/SKILL.md +2 -0
  177. package/skills/apt-execute/SKILL.md +49 -5
  178. package/skills/apt-execute/appendices/tdd-mode.md +107 -0
  179. package/skills/apt-improve/DEEPENING.md +84 -0
  180. package/skills/apt-improve/INTERFACE-DESIGN.md +97 -0
  181. package/skills/apt-improve/LANGUAGE.md +104 -0
  182. package/skills/apt-improve/SKILL.md +141 -0
  183. package/skills/apt-mockup/SKILL.md +2 -0
  184. package/skills/apt-pause/SKILL.md +1 -0
  185. package/skills/apt-personas/SKILL.md +1 -0
  186. package/skills/apt-plan/SKILL.md +149 -4
  187. package/skills/apt-planner.md +42 -1
  188. package/skills/apt-pr-review/SKILL.md +47 -16
  189. package/skills/apt-prototype/LOGIC.md +109 -0
  190. package/skills/apt-prototype/SKILL.md +143 -0
  191. package/skills/apt-prototype/UI.md +90 -0
  192. package/skills/apt-quick/SKILL.md +32 -0
  193. package/skills/apt-resume/SKILL.md +1 -0
  194. package/skills/apt-review/SKILL.md +3 -0
  195. package/skills/apt-roadmap/SKILL.md +1 -0
  196. package/skills/apt-roundtable/SKILL.md +2 -0
  197. package/skills/apt-run/SKILL.md +33 -4
  198. package/skills/apt-scan/SKILL.md +1 -0
  199. package/skills/apt-setup/SKILL.md +129 -2
  200. package/skills/apt-ship/SKILL.md +52 -4
  201. package/skills/apt-stress-test/SKILL.md +1 -0
  202. package/skills/apt-terminal/SKILL.md +1 -0
  203. package/skills/apt-triage/AGENT-BRIEF.md +84 -0
  204. package/skills/apt-triage/OUT-OF-SCOPE.md +75 -0
  205. package/skills/apt-triage/SKILL.md +169 -0
  206. package/skills/apt-update/SKILL.md +3 -0
  207. package/skills/apt-verify/SKILL.md +4 -0
  208. package/skills/apt-verify-proof/SKILL.md +4 -0
  209. package/skills/apt-watch-ci/SKILL.md +163 -0
  210. package/skills/apt-zoom-out/SKILL.md +130 -0
  211. package/src/cli/artifacts/classification.mjs +10 -0
  212. package/src/cli/ci-watch/lock.mjs +178 -0
  213. package/src/cli/ci-watch/state.mjs +103 -0
  214. package/src/cli/ci-watch/stop-matrix.mjs +181 -0
  215. package/src/cli/cli-wrappers/ci-watch.mjs +9 -0
  216. package/src/cli/commands/adr.mjs +243 -0
  217. package/src/cli/commands/ci-watch.mjs +503 -0
  218. package/src/cli/commands/context.mjs +244 -0
  219. package/src/cli/commands/event.mjs +63 -24
  220. package/src/cli/commands/host-detect.mjs +33 -7
  221. package/src/cli/commands/init.mjs +83 -5
  222. package/src/cli/commands/modes.mjs +215 -0
  223. package/src/cli/commands/pr-review-audit-fixer.mjs +95 -16
  224. package/src/cli/commands/route.mjs +11 -2
  225. package/src/cli/commands/task.mjs +152 -18
  226. package/src/cli/commands/tokens.mjs +157 -6
  227. package/src/cli/commands/triage.mjs +277 -0
  228. package/src/cli/config/post-merge-sweep.mjs +49 -3
  229. package/src/cli/consistency/registry.mjs +14 -0
  230. package/src/cli/coordination/agent-identity.mjs +12 -0
  231. package/src/cli/coordination/event-log.mjs +73 -2
  232. package/src/cli/design/frontmatter-schema.mjs +3 -1
  233. package/src/cli/dispatch.mjs +15 -1
  234. package/src/cli/gate/registry.mjs +14 -0
  235. package/src/cli/help.mjs +1 -0
  236. package/src/cli/host/detect.mjs +5 -0
  237. package/src/cli/route/envelope.mjs +140 -106
  238. package/src/cli/route/skill-discover.mjs +46 -1
  239. package/src/cli/skill-author/contract.mjs +29 -0
  240. package/src/cli/skill-author/skill-template.mjs +4 -3
  241. package/src/cli/task/worktree-cleanup.mjs +191 -9
  242. package/templates/adr-format.md +56 -0
  243. package/templates/config.json +4 -0
  244. package/templates/context-format.md +34 -0
@@ -12,13 +12,85 @@
12
12
 
13
13
  import { execFileSync } from 'node:child_process'
14
14
 
15
+ /**
16
+ * Truncate a thrown git error to its first 3 stderr/message lines for
17
+ * surfacing in cleanup envelopes. Extracted from the original inline
18
+ * duplication at the auto-mode merge-error catch.
19
+ *
20
+ * @param {unknown} err
21
+ * @returns {string}
22
+ */
23
+ function shortErr(err) {
24
+ return (err?.stderr || err?.message || '').toString().trim().split('\n').slice(0, 3).join(' ')
25
+ }
26
+
27
+ /**
28
+ * Sanitize an error message for inclusion in returned envelopes: first line
29
+ * only, absolute paths replaced with a placeholder to avoid leaking local
30
+ * filesystem layout.
31
+ *
32
+ * @param {string} msg
33
+ * @returns {string}
34
+ */
35
+ function sanitizeErrMsg(msg) {
36
+ return msg
37
+ .split('\n')[0]
38
+ .replace(/\/[^\s:'"]+/g, '<path>')
39
+ .trim()
40
+ }
41
+
42
+ /**
43
+ * Run `git <args>` with up to 3 attempts and ~200ms backoff when the
44
+ * thrown error's stderr names `.git/index.lock`. Other errors propagate
45
+ * on the first failure. Two concurrent `task close-merged` invocations
46
+ * from different terminals race on git's internal index.lock;
47
+ * retry-on-EEXIST handles that without an app-level mutex (which
48
+ * wouldn't prevent the underlying git race anyway).
49
+ *
50
+ * Sleep uses the same Atomics.wait pattern as withFileLock in
51
+ * util/fs-lock.mjs to park the event loop without spinning the CPU.
52
+ *
53
+ * @param {string[]} args
54
+ * @param {object} opts - forwarded to execFileSync
55
+ * @returns {string} stdout
56
+ */
57
+ function runGitWithRetry(args, opts) {
58
+ const maxAttempts = 3
59
+ const backoffMs = 200
60
+ let lastErr = null
61
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
62
+ try {
63
+ return execFileSync('git', args, opts)
64
+ } catch (err) {
65
+ lastErr = err
66
+ const stderrText = String(err?.stderr ?? '')
67
+ if (!/index\.lock/i.test(stderrText) || attempt === maxAttempts) {
68
+ throw err
69
+ }
70
+ try {
71
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, backoffMs)
72
+ } catch {
73
+ /* runtime without SharedArrayBuffer — fall through, retry immediately */
74
+ }
75
+ }
76
+ }
77
+ // Unreachable — the loop either returns or throws.
78
+ throw lastErr
79
+ }
80
+
15
81
  /**
16
82
  * @param {object} task - closed task record with worktree_path/branch/base_branch.
17
83
  * @param {string} mode - 'never' | 'ask' | 'auto'
18
84
  * @param {string} targetDir - main-repo project directory (cwd for git ops).
85
+ * @param {object} [opts]
86
+ * @param {boolean} [opts.prMerged=false] - true when the PR has been confirmed
87
+ * merged on the remote. Skips local merge-back regardless of merge strategy
88
+ * (merge / squash / rebase). Instead: fetch + ff-only the base branch, then
89
+ * GC worktree + branch. Defaults to false so existing callers retain
90
+ * byte-identical legacy behavior.
19
91
  * @returns {object|null} cleanup report block, or null if no worktree on task.
20
92
  */
21
- export function computeWorktreeCleanup(task, mode, targetDir) {
93
+ export function computeWorktreeCleanup(task, mode, targetDir, opts = {}) {
22
94
  if (!task?.worktree_path) return null
23
95
 
24
96
  const wtPath = task.worktree_path
@@ -36,17 +108,132 @@ export function computeWorktreeCleanup(task, mode, targetDir) {
36
108
  }
37
109
 
38
110
  if (mode === 'ask') {
111
+ // When the PR is already merged on the remote, teach humans the
112
+ // fetch + ff-only recipe instead of the legacy local-merge recipe
113
+ // (which corrupts main when local task ref is stale or the PR used
114
+ // squash/rebase).
115
+ const cleanupCmd =
116
+ opts.prMerged === true
117
+ ? `git fetch origin '${baseBranch}' && git checkout '${baseBranch}' && git merge --ff-only 'origin/${baseBranch}' && git worktree remove '${wtPath}' && git branch -d '${taskBranch}'`
118
+ : `git checkout '${baseBranch}' && git merge --no-edit '${taskBranch}' && git worktree remove '${wtPath}' && git branch -d '${taskBranch}'`
39
119
  return {
40
120
  mode,
41
121
  worktree_path: wtPath,
42
122
  branch: taskBranch,
43
123
  base_branch: baseBranch,
44
124
  action: 'pending',
45
- cleanup_command: `git checkout ${baseBranch} && git merge --no-edit ${taskBranch} && git worktree remove ${wtPath} && git branch -d ${taskBranch}`,
125
+ cleanup_command: cleanupCmd,
126
+ ...(opts.prMerged === true ? { pr_merged_remotely: true } : {}),
127
+ }
128
+ }
129
+
130
+ // mode === 'auto' && opts.prMerged === true.
131
+ // Trust origin as the merge authority. Method-agnostic across merge,
132
+ // squash, and rebase: fetch + checkout + ff-only, then GC. Never
133
+ // local-merge the task branch when GitHub already merged the PR.
134
+ if (opts.prMerged === true) {
135
+ let fetchOk = false
136
+ let ffOk = false
137
+ let branchDeleted = false
138
+ const warnings = []
139
+ try {
140
+ runGitWithRetry(['fetch', 'origin', baseBranch, '--no-tags'], {
141
+ cwd: targetDir,
142
+ encoding: 'utf-8',
143
+ stdio: 'pipe',
144
+ })
145
+ fetchOk = true
146
+ } catch (err) {
147
+ // Offline or network-error. Skip ff-only; user must
148
+ // `git pull --ff-only` later. Cleanup still proceeds.
149
+ warnings.push(`fetch_failed: ${sanitizeErrMsg(shortErr(err))}`)
150
+ }
151
+
152
+ try {
153
+ runGitWithRetry(['checkout', baseBranch], {
154
+ cwd: targetDir,
155
+ encoding: 'utf-8',
156
+ stdio: 'pipe',
157
+ })
158
+ } catch (err) {
159
+ // Couldn't switch to base branch (e.g. fresh clone where base
160
+ // doesn't exist locally). Surface and abort cleanup; preserve
161
+ // local repo state — do NOT GC the worktree+branch.
162
+ return {
163
+ mode,
164
+ worktree_path: wtPath,
165
+ branch: taskBranch,
166
+ base_branch: baseBranch,
167
+ action: 'checkout_failed',
168
+ error: shortErr(err),
169
+ message: `Could not checkout ${baseBranch}; local repo state preserved. Resolve and re-run.`,
170
+ }
171
+ }
172
+
173
+ if (fetchOk) {
174
+ try {
175
+ runGitWithRetry(['merge', '--ff-only', `origin/${baseBranch}`], {
176
+ cwd: targetDir,
177
+ encoding: 'utf-8',
178
+ stdio: 'pipe',
179
+ })
180
+ ffOk = true
181
+ } catch (err) {
182
+ // ff-only failed → local base has commits not on origin. Do
183
+ // NOT auto-resolve; warn and leave local at its current
184
+ // commit. Worktree + branch GC still runs.
185
+ warnings.push(`ff_only_failed: ${sanitizeErrMsg(shortErr(err))}`)
186
+ }
187
+ }
188
+
189
+ try {
190
+ runGitWithRetry(['worktree', 'remove', wtPath], {
191
+ cwd: targetDir,
192
+ encoding: 'utf-8',
193
+ stdio: 'pipe',
194
+ })
195
+ } catch {
196
+ try {
197
+ runGitWithRetry(['worktree', 'remove', '--force', wtPath], {
198
+ cwd: targetDir,
199
+ encoding: 'utf-8',
200
+ stdio: 'pipe',
201
+ })
202
+ } catch {
203
+ /* worktree already gone or unreachable */
204
+ }
205
+ }
206
+ try {
207
+ runGitWithRetry(['branch', '-d', taskBranch], {
208
+ cwd: targetDir,
209
+ encoding: 'utf-8',
210
+ stdio: 'pipe',
211
+ })
212
+ branchDeleted = true
213
+ } catch (err) {
214
+ // Squash/rebase strategies leave the local task branch as
215
+ // "not fully merged" (different SHAs from origin). Surface as
216
+ // a warning rather than force-delete; user can `git branch -D`
217
+ // manually if they want.
218
+ warnings.push(`branch_delete_failed: ${sanitizeErrMsg(shortErr(err))}`)
219
+ }
220
+
221
+ return {
222
+ mode,
223
+ worktree_path: wtPath,
224
+ branch: taskBranch,
225
+ base_branch: baseBranch,
226
+ action: 'pr_merged_remotely_cleaned',
227
+ fetched: fetchOk,
228
+ fast_forwarded: ffOk,
229
+ branch_deleted: branchDeleted,
230
+ ...(warnings.length ? { warnings } : {}),
46
231
  }
47
232
  }
48
233
 
49
- // mode === 'auto' — attempt merge-back in the main repo (never in the worktree).
234
+ // mode === 'auto' (legacy) — attempt merge-back in the main repo
235
+ // (never in the worktree). Direct `task close` callers without
236
+ // --pr-merged-remotely hit this path; byte-identical legacy behavior.
50
237
  let mergeOk = false
51
238
  let mergeError = null
52
239
  try {
@@ -62,12 +249,7 @@ export function computeWorktreeCleanup(task, mode, targetDir) {
62
249
  })
63
250
  mergeOk = true
64
251
  } catch (err) {
65
- mergeError = (err.stderr || err.message || '')
66
- .toString()
67
- .trim()
68
- .split('\n')
69
- .slice(0, 3)
70
- .join(' ')
252
+ mergeError = shortErr(err)
71
253
  // Abort the failed merge so the main repo is left clean.
72
254
  try {
73
255
  execFileSync('git', ['merge', '--abort'], {
@@ -0,0 +1,56 @@
1
+ <!--
2
+ Adapted from Matt Pocock's MIT-licensed skill suite:
3
+ https://github.com/mattpocock/skills/blob/main/skills/engineering/grill-with-docs/ADR-FORMAT.md
4
+ Licensed under MIT. Modifications: ported as the Aperant ADR template
5
+ emitted by `apt-tools adr write` with Nygard's 3-gate filter
6
+ (hard-to-reverse AND surprising-without-context AND real-trade-off).
7
+ -->
8
+
9
+ # ADR-NNNN: {Title}
10
+
11
+ **Status:** {Proposed | Accepted | Deprecated | Superseded}
12
+ **Date:** {YYYY-MM-DD}
13
+
14
+ ## Context
15
+
16
+ {What is the issue that we're seeing that is motivating this decision or
17
+ change? Include enough background that a reader 12 months from now can
18
+ understand WHY this decision was needed without reading the surrounding
19
+ codebase. Cite empirical evidence, prior decisions, or codebase artifacts
20
+ where possible.}
21
+
22
+ ## Decision
23
+
24
+ {What is the change that we're proposing or have agreed to implement?
25
+ State the decision in declarative terms — what WILL be done, not what
26
+ might be considered.}
27
+
28
+ ## Consequences
29
+
30
+ {What becomes easier or harder to do because of this change? Enumerate
31
+ both the positive and negative consequences. The Nygard form is
32
+ deliberately neutral — you list both upsides and downsides so a future
33
+ reader can weigh whether the trade-off still holds.}
34
+
35
+ ---
36
+
37
+ ## Nygard 3-gate filter (audit trail)
38
+
39
+ This ADR was written via `apt-tools adr write` and passed all three of
40
+ Nygard's filter gates. If any one had failed, the decision would have
41
+ stayed in `.aperant/context/notes/{task-id}.md` and no ADR file would
42
+ have been created. The filter prevents ADR pollution — only durable,
43
+ surprising, trade-off-bearing decisions become ADRs.
44
+
45
+ - **Hard to reverse:** {true | false} — Could this be undone in a single
46
+ PR if we changed our minds in 6 months? If "yes, easily" → not an ADR.
47
+ - **Surprising without context:** {true | false} — Would a new
48
+ contributor reading the code be surprised by this choice and want to
49
+ know why? If "no, this is the obvious approach" → not an ADR.
50
+ - **Real trade-off:** {true | false} — Did we genuinely consider an
51
+ alternative and pick the worse-along-one-axis option for a
52
+ better-along-another? If "no, no alternative was real" → not an ADR.
53
+
54
+ Reversible decisions, obvious decisions, and trade-off-free decisions
55
+ all stay in context-notes — they survive the task but don't deserve a
56
+ permanent ADR slot.
@@ -106,6 +106,10 @@
106
106
  "review_mode": "auto",
107
107
  "debate_mode": "auto"
108
108
  },
109
+ "diagram": {
110
+ "mode": "file",
111
+ "mcpConsent": null
112
+ },
109
113
  "docs_policy": {
110
114
  "$comment": "C33 docs-coherence policy. Override via /apt:setup Batch 7. Keys are globs/paths; values are 'auto-update' | 'flag-drift' | 'skip'. Missing block → defaults from packages/framework/templates/docs-policy-defaults.json apply."
111
115
  },
@@ -0,0 +1,34 @@
1
+ <!--
2
+ Adapted from Matt Pocock's MIT-licensed skill suite:
3
+ https://github.com/mattpocock/skills/blob/main/skills/engineering/grill-with-docs/CONTEXT-FORMAT.md
4
+ Licensed under MIT. Modifications: ported as the Aperant CONTEXT.md
5
+ template emitted by `apt-tools context write`. Adds the "Project glossary"
6
+ header and example dialogue section.
7
+ -->
8
+
9
+ # Project glossary (CONTEXT.md)
10
+
11
+ This file is the persistent project glossary. Each term-block carries the
12
+ following fields per Pocock's CONTEXT.md format:
13
+
14
+ - **{Term}** — definition (one line).
15
+ - **Aliases to avoid:** comma-separated synonyms or near-synonyms that
16
+ should NOT be used interchangeably. Prevents conflated-terminology
17
+ bugs that no amount of code review catches.
18
+ - **Cardinality:** one-to-one, one-to-many, many-to-many. When the
19
+ term refers to an entity, this is the relationship to its parent or
20
+ children.
21
+ - **Flagged ambiguities:** any known gray areas where the term is used
22
+ inconsistently in the codebase. Resolving these is part of the
23
+ grill loop.
24
+ - **Example dialogue:** a 1-2 turn example showing how the term is
25
+ used in a sentence (or in a UI label, error message, API field
26
+ name). Anchors the term to surface usage.
27
+
28
+ `apt-tools context write` upserts term-blocks into this file. The writer
29
+ is idempotent — re-running with the same `--term` overwrites the
30
+ existing block in place. Fields not explicitly overridden are preserved.
31
+
32
+ The format intentionally mirrors a domain glossary, not a code glossary.
33
+ Terms are user-facing concepts (e.g., "Plan thread", "Sparring round"),
34
+ not implementation details (e.g., "ChatSession", "useTaskStore").