@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
@@ -1 +1 @@
1
- {"version":3,"file":"skill-template.mjs","sourceRoot":"","sources":["../../../src/cli/skill-author/skill-template.mjs"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE;IACpD,MAAM,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAA;IAC9B,OAAO;QACA,QAAQ;eACD,WAAW;;;;;;;;;kBASR,QAAQ;;;;;;;OAOnB,QAAQ;MACT,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDb,CAAA;AACD,CAAC"}
1
+ {"version":3,"file":"skill-template.mjs","sourceRoot":"","sources":["../../../src/cli/skill-author/skill-template.mjs"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE;IACpD,MAAM,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAA;IAC9B,OAAO;QACA,QAAQ;eACD,WAAW;;;;;;;;;;;;;;kBAcR,QAAQ;;;OAGnB,QAAQ;MACT,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDb,CAAA;AACD,CAAC"}
@@ -2,7 +2,15 @@
2
2
  * @param {object} task - closed task record with worktree_path/branch/base_branch.
3
3
  * @param {string} mode - 'never' | 'ask' | 'auto'
4
4
  * @param {string} targetDir - main-repo project directory (cwd for git ops).
5
+ * @param {object} [opts]
6
+ * @param {boolean} [opts.prMerged=false] - true when the PR has been confirmed
7
+ * merged on the remote. Skips local merge-back regardless of merge strategy
8
+ * (merge / squash / rebase). Instead: fetch + ff-only the base branch, then
9
+ * GC worktree + branch. Defaults to false so existing callers retain
10
+ * byte-identical legacy behavior.
5
11
  * @returns {object|null} cleanup report block, or null if no worktree on task.
6
12
  */
7
- export function computeWorktreeCleanup(task: object, mode: string, targetDir: string): object | null;
13
+ export function computeWorktreeCleanup(task: object, mode: string, targetDir: string, opts?: {
14
+ prMerged?: boolean | undefined;
15
+ }): object | null;
8
16
  //# sourceMappingURL=worktree-cleanup.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worktree-cleanup.d.mts","sourceRoot":"","sources":["../../../src/cli/task/worktree-cleanup.mjs"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,6CALW,MAAM,QACN,MAAM,aACN,MAAM,GACJ,MAAM,GAAC,IAAI,CA8GvB"}
1
+ {"version":3,"file":"worktree-cleanup.d.mts","sourceRoot":"","sources":["../../../src/cli/task/worktree-cleanup.mjs"],"names":[],"mappings":"AAgFA;;;;;;;;;;;GAWG;AACH,6CAXW,MAAM,QACN,MAAM,aACN,MAAM,SAEd;IAAuB,QAAQ;CAK/B,GAAU,MAAM,GAAC,IAAI,CA4NvB"}
@@ -10,13 +10,84 @@
10
10
  * 'auto' → merge back into base_branch, then remove the worktree + branch
11
11
  */
12
12
  import { execFileSync } from 'node:child_process';
13
+ /**
14
+ * Truncate a thrown git error to its first 3 stderr/message lines for
15
+ * surfacing in cleanup envelopes. Extracted from the original inline
16
+ * duplication at the auto-mode merge-error catch.
17
+ *
18
+ * @param {unknown} err
19
+ * @returns {string}
20
+ */
21
+ function shortErr(err) {
22
+ return (err?.stderr || err?.message || '').toString().trim().split('\n').slice(0, 3).join(' ');
23
+ }
24
+ /**
25
+ * Sanitize an error message for inclusion in returned envelopes: first line
26
+ * only, absolute paths replaced with a placeholder to avoid leaking local
27
+ * filesystem layout.
28
+ *
29
+ * @param {string} msg
30
+ * @returns {string}
31
+ */
32
+ function sanitizeErrMsg(msg) {
33
+ return msg
34
+ .split('\n')[0]
35
+ .replace(/\/[^\s:'"]+/g, '<path>')
36
+ .trim();
37
+ }
38
+ /**
39
+ * Run `git <args>` with up to 3 attempts and ~200ms backoff when the
40
+ * thrown error's stderr names `.git/index.lock`. Other errors propagate
41
+ * on the first failure. Two concurrent `task close-merged` invocations
42
+ * from different terminals race on git's internal index.lock;
43
+ * retry-on-EEXIST handles that without an app-level mutex (which
44
+ * wouldn't prevent the underlying git race anyway).
45
+ *
46
+ * Sleep uses the same Atomics.wait pattern as withFileLock in
47
+ * util/fs-lock.mjs to park the event loop without spinning the CPU.
48
+ *
49
+ * @param {string[]} args
50
+ * @param {object} opts - forwarded to execFileSync
51
+ * @returns {string} stdout
52
+ */
53
+ function runGitWithRetry(args, opts) {
54
+ const maxAttempts = 3;
55
+ const backoffMs = 200;
56
+ let lastErr = null;
57
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
58
+ try {
59
+ return execFileSync('git', args, opts);
60
+ }
61
+ catch (err) {
62
+ lastErr = err;
63
+ const stderrText = String(err?.stderr ?? '');
64
+ if (!/index\.lock/i.test(stderrText) || attempt === maxAttempts) {
65
+ throw err;
66
+ }
67
+ try {
68
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, backoffMs);
69
+ }
70
+ catch {
71
+ /* runtime without SharedArrayBuffer — fall through, retry immediately */
72
+ }
73
+ }
74
+ }
75
+ // Unreachable — the loop either returns or throws.
76
+ throw lastErr;
77
+ }
13
78
  /**
14
79
  * @param {object} task - closed task record with worktree_path/branch/base_branch.
15
80
  * @param {string} mode - 'never' | 'ask' | 'auto'
16
81
  * @param {string} targetDir - main-repo project directory (cwd for git ops).
82
+ * @param {object} [opts]
83
+ * @param {boolean} [opts.prMerged=false] - true when the PR has been confirmed
84
+ * merged on the remote. Skips local merge-back regardless of merge strategy
85
+ * (merge / squash / rebase). Instead: fetch + ff-only the base branch, then
86
+ * GC worktree + branch. Defaults to false so existing callers retain
87
+ * byte-identical legacy behavior.
17
88
  * @returns {object|null} cleanup report block, or null if no worktree on task.
18
89
  */
19
- export function computeWorktreeCleanup(task, mode, targetDir) {
90
+ export function computeWorktreeCleanup(task, mode, targetDir, opts = {}) {
20
91
  if (!task?.worktree_path)
21
92
  return null;
22
93
  const wtPath = task.worktree_path;
@@ -32,16 +103,131 @@ export function computeWorktreeCleanup(task, mode, targetDir) {
32
103
  };
33
104
  }
34
105
  if (mode === 'ask') {
106
+ // When the PR is already merged on the remote, teach humans the
107
+ // fetch + ff-only recipe instead of the legacy local-merge recipe
108
+ // (which corrupts main when local task ref is stale or the PR used
109
+ // squash/rebase).
110
+ const cleanupCmd = opts.prMerged === true
111
+ ? `git fetch origin '${baseBranch}' && git checkout '${baseBranch}' && git merge --ff-only 'origin/${baseBranch}' && git worktree remove '${wtPath}' && git branch -d '${taskBranch}'`
112
+ : `git checkout '${baseBranch}' && git merge --no-edit '${taskBranch}' && git worktree remove '${wtPath}' && git branch -d '${taskBranch}'`;
35
113
  return {
36
114
  mode,
37
115
  worktree_path: wtPath,
38
116
  branch: taskBranch,
39
117
  base_branch: baseBranch,
40
118
  action: 'pending',
41
- cleanup_command: `git checkout ${baseBranch} && git merge --no-edit ${taskBranch} && git worktree remove ${wtPath} && git branch -d ${taskBranch}`,
119
+ cleanup_command: cleanupCmd,
120
+ ...(opts.prMerged === true ? { pr_merged_remotely: true } : {}),
121
+ };
122
+ }
123
+ // mode === 'auto' && opts.prMerged === true.
124
+ // Trust origin as the merge authority. Method-agnostic across merge,
125
+ // squash, and rebase: fetch + checkout + ff-only, then GC. Never
126
+ // local-merge the task branch when GitHub already merged the PR.
127
+ if (opts.prMerged === true) {
128
+ let fetchOk = false;
129
+ let ffOk = false;
130
+ let branchDeleted = false;
131
+ const warnings = [];
132
+ try {
133
+ runGitWithRetry(['fetch', 'origin', baseBranch, '--no-tags'], {
134
+ cwd: targetDir,
135
+ encoding: 'utf-8',
136
+ stdio: 'pipe',
137
+ });
138
+ fetchOk = true;
139
+ }
140
+ catch (err) {
141
+ // Offline or network-error. Skip ff-only; user must
142
+ // `git pull --ff-only` later. Cleanup still proceeds.
143
+ warnings.push(`fetch_failed: ${sanitizeErrMsg(shortErr(err))}`);
144
+ }
145
+ try {
146
+ runGitWithRetry(['checkout', baseBranch], {
147
+ cwd: targetDir,
148
+ encoding: 'utf-8',
149
+ stdio: 'pipe',
150
+ });
151
+ }
152
+ catch (err) {
153
+ // Couldn't switch to base branch (e.g. fresh clone where base
154
+ // doesn't exist locally). Surface and abort cleanup; preserve
155
+ // local repo state — do NOT GC the worktree+branch.
156
+ return {
157
+ mode,
158
+ worktree_path: wtPath,
159
+ branch: taskBranch,
160
+ base_branch: baseBranch,
161
+ action: 'checkout_failed',
162
+ error: shortErr(err),
163
+ message: `Could not checkout ${baseBranch}; local repo state preserved. Resolve and re-run.`,
164
+ };
165
+ }
166
+ if (fetchOk) {
167
+ try {
168
+ runGitWithRetry(['merge', '--ff-only', `origin/${baseBranch}`], {
169
+ cwd: targetDir,
170
+ encoding: 'utf-8',
171
+ stdio: 'pipe',
172
+ });
173
+ ffOk = true;
174
+ }
175
+ catch (err) {
176
+ // ff-only failed → local base has commits not on origin. Do
177
+ // NOT auto-resolve; warn and leave local at its current
178
+ // commit. Worktree + branch GC still runs.
179
+ warnings.push(`ff_only_failed: ${sanitizeErrMsg(shortErr(err))}`);
180
+ }
181
+ }
182
+ try {
183
+ runGitWithRetry(['worktree', 'remove', wtPath], {
184
+ cwd: targetDir,
185
+ encoding: 'utf-8',
186
+ stdio: 'pipe',
187
+ });
188
+ }
189
+ catch {
190
+ try {
191
+ runGitWithRetry(['worktree', 'remove', '--force', wtPath], {
192
+ cwd: targetDir,
193
+ encoding: 'utf-8',
194
+ stdio: 'pipe',
195
+ });
196
+ }
197
+ catch {
198
+ /* worktree already gone or unreachable */
199
+ }
200
+ }
201
+ try {
202
+ runGitWithRetry(['branch', '-d', taskBranch], {
203
+ cwd: targetDir,
204
+ encoding: 'utf-8',
205
+ stdio: 'pipe',
206
+ });
207
+ branchDeleted = true;
208
+ }
209
+ catch (err) {
210
+ // Squash/rebase strategies leave the local task branch as
211
+ // "not fully merged" (different SHAs from origin). Surface as
212
+ // a warning rather than force-delete; user can `git branch -D`
213
+ // manually if they want.
214
+ warnings.push(`branch_delete_failed: ${sanitizeErrMsg(shortErr(err))}`);
215
+ }
216
+ return {
217
+ mode,
218
+ worktree_path: wtPath,
219
+ branch: taskBranch,
220
+ base_branch: baseBranch,
221
+ action: 'pr_merged_remotely_cleaned',
222
+ fetched: fetchOk,
223
+ fast_forwarded: ffOk,
224
+ branch_deleted: branchDeleted,
225
+ ...(warnings.length ? { warnings } : {}),
42
226
  };
43
227
  }
44
- // mode === 'auto' — attempt merge-back in the main repo (never in the worktree).
228
+ // mode === 'auto' (legacy) — attempt merge-back in the main repo
229
+ // (never in the worktree). Direct `task close` callers without
230
+ // --pr-merged-remotely hit this path; byte-identical legacy behavior.
45
231
  let mergeOk = false;
46
232
  let mergeError = null;
47
233
  try {
@@ -58,12 +244,7 @@ export function computeWorktreeCleanup(task, mode, targetDir) {
58
244
  mergeOk = true;
59
245
  }
60
246
  catch (err) {
61
- mergeError = (err.stderr || err.message || '')
62
- .toString()
63
- .trim()
64
- .split('\n')
65
- .slice(0, 3)
66
- .join(' ');
247
+ mergeError = shortErr(err);
67
248
  // Abort the failed merge so the main repo is left clean.
68
249
  try {
69
250
  execFileSync('git', ['merge', '--abort'], {
@@ -1 +1 @@
1
- {"version":3,"file":"worktree-cleanup.mjs","sourceRoot":"","sources":["../../../src/cli/task/worktree-cleanup.mjs"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worktree-cleanup.mjs","sourceRoot":"","sources":["../../../src/cli/task/worktree-cleanup.mjs"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aperant",
3
- "version": "0.5.0",
3
+ "version": "0.6.4",
4
4
  "description": "AI coding framework — composable skills for planning, executing, verifying, and reviewing code with any LLM provider. Works as Claude Code commands, Codex tasks, or programmatically.",
5
5
  "author": {
6
6
  "name": "Mikalsen AI",
@@ -26,7 +26,7 @@ Before planning, discover project context:
26
26
 
27
27
  **Rationalizations (R4):** Read `.aperant/rationalizations/claude-opus-4-6.md` once at session start. It catalogues observed planner failure modes — especially ceremonialization (plan prose treated as progress) and postcondition triviality (`postcondition: "true"` rubber stamps). Every postcondition you emit must be a real, evaluable predicate.
28
28
 
29
- **Multi-runtime install awareness:** Plans that touch shipped framework files (skills/agents/hooks under `packages/framework/`) must respect the multi-runtime install pipeline. Each canonical file ships with an `apt-skill-version: {{APT_VERSION}}` header (substituted at install time) and is reflected in per-runtime `apt-file-manifest.json` files. Drift is detected per-file (header_mismatch, hash_mismatch, missing_header, missing_file) by `apt-tools check-version` — not via a single global version string. After modifying any canonical file, callers must re-run `apt-tools init . --<runtime>` (or `/apt:update`) so the manifest stays in sync.
29
+ **Multi-runtime install awareness:** Plans that touch shipped framework files (skills/agents/hooks under `packages/framework/`) must respect the multi-runtime install pipeline. Each canonical file ships with an `apt-skill-version: {{APT_VERSION}}` header (substituted at install time) and is reflected in per-runtime `apt-file-manifest.json` files. Drift is detected per-file (header_mismatch, hash_mismatch, missing_header, missing_file) by `apt-tools check-version` — not via a single global version string. After modifying any canonical file, callers must re-run `apt-tools init . --<runtime>` (or `/apt:update`) so the manifest stays in sync. **Note (0.6.1):** when an agent re-runs install, the call must include `--team`/`--solo` plus the runtime flag (or `--yes`) — non-TTY `init` no longer silently defaults to `visibility:'solo'`. Without an explicit Class A flag the command exits 2 with a `requires_input` envelope.
30
30
  </project_context>
31
31
 
32
32
  <environment>
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -139,13 +140,118 @@ Show current state summary and autonomy flags (`--supervised`, `--guided`, `--au
139
140
 
140
141
  The user invoked a specific skill by name (e.g., `/apt plan`, `/apt resume`,
141
142
  `/apt:ship`). The router matched the first word against the installed skill
142
- set and filled in `skill`, `skill_args`, `spawn_agent`, and `agent`.
143
+ set and filled in `skill`, `skill_args`, `spawn_agent`, `agent`, AND
144
+ `task_context` + (optional) `default_track`.
143
145
 
144
- **If `spawn_agent` is true:**
145
- Spawn the appropriate agent from the routing result. Pass `skill_args` as context.
146
+ Dispatch on `task_context` never just on `spawn_agent`. The four-branch
147
+ policy below is hardcoded contract; do NOT improvise. See
148
+ `docs/frameworks/spec-gaps.md#g25` for the defect that motivated this.
146
149
 
147
- **If `spawn_agent` is false:**
148
- Invoke the skill directly: call `apt:{skill}` with `skill_args`.
150
+ ### Missing `task_context` fail-closed
151
+
152
+ When the envelope's `task_context` is null (the `?? null` fallback in
153
+ `route.mjs:skillIndex.taskContextOf`), print verbatim and STOP. Do NOT
154
+ invoke the skill:
155
+
156
+ ```
157
+ [APT] ERROR — skill "apt:{skill}" has no task_context declared in SKILL.md frontmatter.
158
+ Cannot dispatch safely until the policy is set. Run /apt:author-skill validate
159
+ packages/framework/skills/apt-{skill}/SKILL.md to see required keys.
160
+ ```
161
+
162
+ **Note:** In practice, a skill missing `task_context` is dropped by
163
+ `discoverSkills` during the Zod schema validation step and will never reach
164
+ the skill-passthrough branch — it will be absent from `knownSlugs`. The
165
+ user sees the skill disappear silently from routing; run
166
+ `apt-tools route .` to surface dropped skills logged to
167
+ `.aperant/logs/route-dropped.jsonl`. The `task_context: null` path is
168
+ reachable if the field is marked optional in a future schema version —
169
+ this error fires in that case.
170
+
171
+ ### `task_context = none`
172
+
173
+ No task semantics. Invoke the skill directly with `skill_args` (or spawn
174
+ `agent` when `spawn_agent` is true). No `task create`, no worktree banner.
175
+
176
+ ### `task_context = self-managed`
177
+
178
+ The skill manages its own task / worktree lifecycle (e.g. `apt:run` calls
179
+ `task create` in its own Step 2; `apt:pr-review` sets up a PR-scoped
180
+ worktree). Dispatch identically to `none` — the skill's own SKILL.md is
181
+ responsible for any task record + worktree banner.
182
+
183
+ ### `task_context = create-new`
184
+
185
+ Resolve the track, then create a fresh task record before invoking the skill.
186
+
187
+ **Track resolution chain (first match wins):**
188
+
189
+ 1. Explicit user flag in `skill_args` — `--quick` → `QUICK`, `--deep` → `DEEP`,
190
+ `--debug` → `DEBUG`.
191
+ 2. `envelope.default_track` if present (the skill's declared default).
192
+ 3. Per-slug hardcoded fallback:
193
+ - `quick` → `QUICK`
194
+ - `debug` → `DEBUG`
195
+ - `plan` → `STANDARD`
196
+ - everything else with `task_context: create-new` → `STANDARD`
197
+
198
+ Then run:
199
+
200
+ ```bash
201
+ node packages/framework/bin/apt-tools.mjs task create . --description "{slug}" --track {track} --autonomy {autonomy} [--scope {scope}]
202
+ ```
203
+
204
+ **Security note:** Do NOT interpolate `{skill_args}` directly into `--description "..."`. `skill_args` is verbatim user input and can contain double-quote characters that break out of the argument boundary and inject extra flags (e.g. `--autonomy`, `--scope`). The task slug is sufficient as the description; `skill_args` is passed to the skill separately after the task record is created.
205
+
206
+ (Use `--scope framework` only when the user is on a framework-scoped task —
207
+ otherwise omit and let the default `project` scope apply.)
208
+
209
+ Parse `task_id`, `task_dir`, and (if present) `worktree.worktree_path` /
210
+ `worktree.branch` / `worktree.base_branch` from the result. Print the
211
+ worktree banner when `worktree` is returned:
212
+
213
+ ```
214
+ [APT] Working in isolated worktree: {worktree_path}
215
+ [APT] Task branch: {branch} (from {base_branch})
216
+ ```
217
+
218
+ Then invoke `apt:{skill}` with `skill_args` + the new task context
219
+ (`task_id`, `task_dir`, `worktree_path`). When `spawn_agent` is true, spawn
220
+ `agent` with the same context.
221
+
222
+ ### `task_context = require-existing`
223
+
224
+ Resolve which active task this invocation refers to, then dispatch. Read
225
+ `state.active_tasks` from `.aperant/state.json`.
226
+
227
+ **Active-task resolution chain (first match wins):**
228
+
229
+ 1. `--task-id <id>` flag present in `skill_args` → use it. If `<id>` is not
230
+ in `state.active_tasks`, error and stop.
231
+ 2. `state.active_tasks` has exactly one entry AND that entry's
232
+ `lifecycle_phase` is non-terminal (`planning`, `executing`, `verifying`,
233
+ `reviewing`) → use it. If the single entry is in a terminal phase
234
+ (`shipped-pending-merge` or `rejected`), fall through to step 4.
235
+ 3. `state.active_tasks` has more than one entry with exactly one in a
236
+ non-terminal lifecycle phase (`planning`, `executing`, `verifying`,
237
+ `reviewing`) → use it.
238
+ (Terminal phases in `active_tasks` are `shipped-pending-merge` and
239
+ `rejected`. Note: `completed` tasks are removed from `active_tasks`
240
+ entirely at close and can never appear here.)
241
+ 4. Otherwise, print the numbered menu and STOP. Auto-mode (autonomy 2/3)
242
+ does NOT bypass this prompt — multi-task ambiguity is the user's call,
243
+ never the framework's guess:
244
+
245
+ ```
246
+ [APT] Multiple active tasks — pick one with `--task-id <id>`:
247
+ 1. {task-id-1} {description} ({lifecycle_phase})
248
+ 2. {task-id-2} {description} ({lifecycle_phase})
249
+ ...
250
+ ```
251
+
252
+ Once resolved, print the worktree banner if the task has a `worktree_path`,
253
+ then invoke `apt:{skill}` with `skill_args` + the resolved `task_id`. When
254
+ `spawn_agent` is true, spawn `agent` with the same context.
149
255
 
150
256
  ---
151
257
 
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
12
13
  default_execution_mode: step
13
14
  execution_modes:
14
15
  - auto
@@ -129,6 +130,16 @@ the author sees the full checklist of gaps to fill. Group by section:
129
130
  The generated structural test only checks tags and numbered steps — the
130
131
  TODOs are the semantic gaps the author must close.
131
132
 
133
+ **Required frontmatter field — `task_context`.** The scaffold ships with
134
+ `task_context: create-new` as the safest default (the new skill will get a
135
+ fresh task record + worktree via `apt-tools task create` when invoked as
136
+ `/apt <slug>`). Verify this is correct for your skill before merging — the
137
+ allowed values are `create-new | require-existing | self-managed | none`.
138
+ See `packages/framework/docs/skill-passthrough.md` for the four-policy
139
+ contract and the orchestrator dispatch behavior. Missing or wrong values
140
+ are caught by the structural test in
141
+ `packages/framework/src/__tests__/skill-frontmatter-task-context.test.ts`.
142
+
132
143
  ## 4. Show the Structural Test
133
144
 
134
145
  Read the generated structural test file and echo its contents so the
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: false
9
9
  internal: true
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: require-existing
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: true
11
11
  agent_name: apt-docs-author
12
+ task_context: create-new
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: DEBUG
12
14
  default_execution_mode: auto
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: STANDARD
12
14
  default_execution_mode: step
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: STANDARD
12
14
  default_execution_mode: step
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: STANDARD
12
14
  default_execution_mode: auto
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: true
11
11
  agent_name: "apt-executor"
12
+ task_context: require-existing
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: STANDARD
12
14
  default_execution_mode: step
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: true
11
11
  agent_name: "apt-planner"
12
+ task_context: create-new
13
+ default_track: STANDARD
12
14
  default_execution_mode: auto
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: self-managed
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: QUICK
12
14
  default_execution_mode: auto
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: true
11
11
  agent_name: "apt-reviewer"
12
+ task_context: require-existing
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: none
12
13
  default_execution_mode: step
13
14
  execution_modes:
14
15
  - auto
@@ -9,6 +9,8 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: create-new
13
+ default_track: DEEP
12
14
  default_execution_mode: auto
13
15
  execution_modes:
14
16
  - auto
@@ -9,6 +9,7 @@ user_invocable: true
9
9
  internal: false
10
10
  spawns_agent: false
11
11
  agent_name: null
12
+ task_context: self-managed
12
13
  default_execution_mode: auto
13
14
  execution_modes:
14
15
  - auto