@aperant/framework 0.6.7 → 0.7.3

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 (205) hide show
  1. package/CHANGELOG.md +240 -0
  2. package/agents/apt-planner.md +12 -0
  3. package/agents/apt-pr-review-fixer.md +13 -9
  4. package/bin/apt-tools.mjs +7 -0
  5. package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -1
  6. package/dist/cli/ci-watch/stop-matrix.mjs +16 -0
  7. package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -1
  8. package/dist/cli/commands/ci-watch.d.mts +11 -0
  9. package/dist/cli/commands/ci-watch.d.mts.map +1 -1
  10. package/dist/cli/commands/ci-watch.mjs +147 -3
  11. package/dist/cli/commands/ci-watch.mjs.map +1 -1
  12. package/dist/cli/commands/features-audit.d.mts +24 -0
  13. package/dist/cli/commands/features-audit.d.mts.map +1 -1
  14. package/dist/cli/commands/features-audit.mjs +159 -5
  15. package/dist/cli/commands/features-audit.mjs.map +1 -1
  16. package/dist/cli/commands/health-check.d.mts +16 -0
  17. package/dist/cli/commands/health-check.d.mts.map +1 -1
  18. package/dist/cli/commands/health-check.mjs +119 -3
  19. package/dist/cli/commands/health-check.mjs.map +1 -1
  20. package/dist/cli/commands/init.d.mts +19 -1
  21. package/dist/cli/commands/init.d.mts.map +1 -1
  22. package/dist/cli/commands/init.mjs +143 -8
  23. package/dist/cli/commands/init.mjs.map +1 -1
  24. package/dist/cli/commands/modes.d.mts.map +1 -1
  25. package/dist/cli/commands/modes.mjs +11 -0
  26. package/dist/cli/commands/modes.mjs.map +1 -1
  27. package/dist/cli/commands/pr-review-audit-fixer.d.mts +13 -0
  28. package/dist/cli/commands/pr-review-audit-fixer.d.mts.map +1 -1
  29. package/dist/cli/commands/pr-review-audit-fixer.mjs +18 -5
  30. package/dist/cli/commands/pr-review-audit-fixer.mjs.map +1 -1
  31. package/dist/cli/commands/route.d.mts.map +1 -1
  32. package/dist/cli/commands/route.mjs +37 -2
  33. package/dist/cli/commands/route.mjs.map +1 -1
  34. package/dist/cli/commands/task.d.mts.map +1 -1
  35. package/dist/cli/commands/task.mjs +132 -5
  36. package/dist/cli/commands/task.mjs.map +1 -1
  37. package/dist/cli/commands/validate-evidence.d.mts +24 -2
  38. package/dist/cli/commands/validate-evidence.d.mts.map +1 -1
  39. package/dist/cli/commands/validate-evidence.mjs +154 -17
  40. package/dist/cli/commands/validate-evidence.mjs.map +1 -1
  41. package/dist/cli/commands/vitest-doctor.d.mts +2 -0
  42. package/dist/cli/commands/vitest-doctor.d.mts.map +1 -0
  43. package/dist/cli/commands/vitest-doctor.mjs +168 -0
  44. package/dist/cli/commands/vitest-doctor.mjs.map +1 -0
  45. package/dist/cli/config/gitignore-drift.d.mts +23 -1
  46. package/dist/cli/config/gitignore-drift.d.mts.map +1 -1
  47. package/dist/cli/config/gitignore-drift.mjs +81 -3
  48. package/dist/cli/config/gitignore-drift.mjs.map +1 -1
  49. package/dist/cli/config/load.d.mts +56 -2
  50. package/dist/cli/config/load.d.mts.map +1 -1
  51. package/dist/cli/config/load.mjs +192 -2
  52. package/dist/cli/config/load.mjs.map +1 -1
  53. package/dist/cli/consistency/parse-review.mjs +7 -0
  54. package/dist/cli/consistency/parse-review.mjs.map +1 -1
  55. package/dist/cli/dispatch.d.mts.map +1 -1
  56. package/dist/cli/dispatch.mjs +24 -2
  57. package/dist/cli/dispatch.mjs.map +1 -1
  58. package/dist/cli/gate/gates/gitignore-in-sync.d.mts +1 -1
  59. package/dist/cli/gate/gates/gitignore-in-sync.d.mts.map +1 -1
  60. package/dist/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  61. package/dist/cli/gate/gates/gitignore-in-sync.mjs.map +1 -1
  62. package/dist/cli/gate/gates/review-clean.d.mts +5 -1
  63. package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
  64. package/dist/cli/gate/gates/review-clean.mjs +23 -18
  65. package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
  66. package/dist/cli/gate/gates/verify-approved.d.mts +49 -1
  67. package/dist/cli/gate/gates/verify-approved.d.mts.map +1 -1
  68. package/dist/cli/gate/gates/verify-approved.mjs +93 -14
  69. package/dist/cli/gate/gates/verify-approved.mjs.map +1 -1
  70. package/dist/cli/help.d.mts.map +1 -1
  71. package/dist/cli/help.mjs +8 -2
  72. package/dist/cli/help.mjs.map +1 -1
  73. package/dist/cli/host/detect.d.mts +122 -9
  74. package/dist/cli/host/detect.d.mts.map +1 -1
  75. package/dist/cli/host/detect.mjs +132 -0
  76. package/dist/cli/host/detect.mjs.map +1 -1
  77. package/dist/cli/install/legacy-paths.d.mts +38 -0
  78. package/dist/cli/install/legacy-paths.d.mts.map +1 -0
  79. package/dist/cli/install/legacy-paths.mjs +69 -0
  80. package/dist/cli/install/legacy-paths.mjs.map +1 -0
  81. package/dist/cli/install/runtime-detect.d.mts +13 -0
  82. package/dist/cli/install/runtime-detect.d.mts.map +1 -1
  83. package/dist/cli/install/runtime-detect.mjs +9 -0
  84. package/dist/cli/install/runtime-detect.mjs.map +1 -1
  85. package/dist/cli/install/runtime-migrate.d.mts +84 -0
  86. package/dist/cli/install/runtime-migrate.d.mts.map +1 -0
  87. package/dist/cli/install/runtime-migrate.mjs +244 -0
  88. package/dist/cli/install/runtime-migrate.mjs.map +1 -0
  89. package/dist/cli/route/drift-detect.d.mts +20 -0
  90. package/dist/cli/route/drift-detect.d.mts.map +1 -0
  91. package/dist/cli/route/drift-detect.mjs +107 -0
  92. package/dist/cli/route/drift-detect.mjs.map +1 -0
  93. package/dist/cli/task/index-md.d.mts.map +1 -1
  94. package/dist/cli/task/index-md.mjs +14 -2
  95. package/dist/cli/task/index-md.mjs.map +1 -1
  96. package/dist/cli/util/aperant-section.d.mts +34 -0
  97. package/dist/cli/util/aperant-section.d.mts.map +1 -0
  98. package/dist/cli/util/aperant-section.mjs +127 -0
  99. package/dist/cli/util/aperant-section.mjs.map +1 -0
  100. package/dist/cli/util/copy.d.mts +28 -1
  101. package/dist/cli/util/copy.d.mts.map +1 -1
  102. package/dist/cli/util/copy.mjs +43 -55
  103. package/dist/cli/util/copy.mjs.map +1 -1
  104. package/dist/cli/util/semver.d.mts +17 -0
  105. package/dist/cli/util/semver.d.mts.map +1 -0
  106. package/dist/cli/util/semver.mjs +29 -0
  107. package/dist/cli/util/semver.mjs.map +1 -0
  108. package/dist/cli/util/skill-installs.d.mts +65 -9
  109. package/dist/cli/util/skill-installs.d.mts.map +1 -1
  110. package/dist/cli/util/skill-installs.mjs +130 -21
  111. package/dist/cli/util/skill-installs.mjs.map +1 -1
  112. package/dist/cli/util/version-preflight.d.mts +44 -0
  113. package/dist/cli/util/version-preflight.d.mts.map +1 -0
  114. package/dist/cli/util/version-preflight.mjs +66 -0
  115. package/dist/cli/util/version-preflight.mjs.map +1 -0
  116. package/dist/plugin/.claude-plugin/plugin.json +11 -2
  117. package/dist/plugin/agents/apt-improver.md +99 -0
  118. package/dist/plugin/agents/apt-planner.md +127 -10
  119. package/dist/plugin/agents/apt-pr-review-fixer.md +13 -9
  120. package/dist/plugin/skills/apt/SKILL.md +1 -0
  121. package/dist/plugin/skills/apt-close-task/SKILL.md +63 -1
  122. package/dist/plugin/skills/apt-debug/SKILL.md +39 -6
  123. package/dist/plugin/skills/apt-debug/appendices/diagnose-discipline.md +119 -0
  124. package/dist/plugin/skills/apt-diagram/SKILL.md +378 -0
  125. package/dist/plugin/skills/apt-diagram/appendices/design-discipline.md +97 -0
  126. package/dist/plugin/skills/apt-discuss/SKILL.md +72 -5
  127. package/dist/plugin/skills/apt-discuss/appendices/grill-discipline.md +104 -0
  128. package/dist/plugin/skills/apt-discuss/appendices/zoom-out-helper.md +79 -0
  129. package/dist/plugin/skills/apt-execute/SKILL.md +57 -5
  130. package/dist/plugin/skills/apt-execute/appendices/tdd-mode.md +107 -0
  131. package/dist/plugin/skills/apt-improve/DEEPENING.md +84 -0
  132. package/dist/plugin/skills/apt-improve/INTERFACE-DESIGN.md +97 -0
  133. package/dist/plugin/skills/apt-improve/LANGUAGE.md +104 -0
  134. package/dist/plugin/skills/apt-improve/SKILL.md +141 -0
  135. package/dist/plugin/skills/apt-plan/SKILL.md +171 -4
  136. package/dist/plugin/skills/apt-plan/adapters/conductor.md +98 -0
  137. package/dist/plugin/skills/apt-pr-review/SKILL.md +57 -18
  138. package/dist/plugin/skills/apt-prototype/LOGIC.md +109 -0
  139. package/dist/plugin/skills/apt-prototype/SKILL.md +143 -0
  140. package/dist/plugin/skills/apt-prototype/UI.md +90 -0
  141. package/dist/plugin/skills/apt-quick/SKILL.md +49 -8
  142. package/dist/plugin/skills/apt-release-notes/SKILL.md +193 -0
  143. package/dist/plugin/skills/apt-release-notes/appendices/persona-voice.md +59 -0
  144. package/dist/plugin/skills/apt-review/SKILL.md +2 -0
  145. package/dist/plugin/skills/apt-run/SKILL.md +32 -4
  146. package/dist/plugin/skills/apt-setup/SKILL.md +308 -6
  147. package/dist/plugin/skills/apt-ship/SKILL.md +122 -1
  148. package/dist/plugin/skills/apt-spar/SKILL.md +315 -0
  149. package/dist/plugin/skills/apt-triage/AGENT-BRIEF.md +84 -0
  150. package/dist/plugin/skills/apt-triage/OUT-OF-SCOPE.md +75 -0
  151. package/dist/plugin/skills/apt-triage/SKILL.md +169 -0
  152. package/dist/plugin/skills/apt-update/SKILL.md +77 -10
  153. package/dist/plugin/skills/apt-verify/SKILL.md +3 -0
  154. package/dist/plugin/skills/apt-verify-proof/SKILL.md +10 -5
  155. package/dist/plugin/skills/apt-watch-ci/SKILL.md +166 -0
  156. package/dist/plugin/skills/apt-zoom-out/SKILL.md +130 -0
  157. package/package.json +133 -133
  158. package/prompts/conductor-framework-context.md +63 -0
  159. package/prompts/conductor-system.md +11 -0
  160. package/skills/apt-close-task/SKILL.md +6 -0
  161. package/skills/apt-discuss/SKILL.md +47 -5
  162. package/skills/apt-execute/SKILL.md +9 -0
  163. package/skills/apt-plan/SKILL.md +12 -0
  164. package/skills/apt-pr-review/SKILL.md +11 -2
  165. package/skills/apt-quick/SKILL.md +19 -8
  166. package/skills/apt-researcher.md +1 -0
  167. package/skills/apt-setup/SKILL.md +33 -2
  168. package/skills/apt-ship/SKILL.md +16 -4
  169. package/skills/apt-spar/SKILL.md +36 -11
  170. package/skills/apt-update/SKILL.md +26 -1
  171. package/skills/apt-verify-proof/SKILL.md +7 -5
  172. package/skills/apt-watch-ci/SKILL.md +4 -1
  173. package/src/cli/ci-watch/stop-matrix.mjs +17 -0
  174. package/src/cli/commands/ci-watch.mjs +152 -3
  175. package/src/cli/commands/features-audit.mjs +164 -5
  176. package/src/cli/commands/health-check.mjs +116 -3
  177. package/src/cli/commands/init.mjs +154 -6
  178. package/src/cli/commands/modes.mjs +11 -0
  179. package/src/cli/commands/pr-review-audit-fixer.mjs +18 -5
  180. package/src/cli/commands/route.mjs +38 -2
  181. package/src/cli/commands/task.mjs +132 -5
  182. package/src/cli/commands/validate-evidence.mjs +158 -17
  183. package/src/cli/commands/vitest-doctor.mjs +173 -0
  184. package/src/cli/config/gitignore-drift.mjs +74 -3
  185. package/src/cli/config/load.mjs +188 -2
  186. package/src/cli/consistency/parse-review.mjs +6 -0
  187. package/src/cli/dispatch.mjs +23 -2
  188. package/src/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  189. package/src/cli/gate/gates/review-clean.mjs +24 -19
  190. package/src/cli/gate/gates/verify-approved.mjs +97 -14
  191. package/src/cli/help.mjs +8 -2
  192. package/src/cli/host/detect.mjs +135 -0
  193. package/src/cli/install/legacy-paths.mjs +69 -0
  194. package/src/cli/install/runtime-detect.mjs +9 -0
  195. package/src/cli/install/runtime-migrate.mjs +252 -0
  196. package/src/cli/route/drift-detect.mjs +107 -0
  197. package/src/cli/task/index-md.mjs +15 -2
  198. package/src/cli/util/aperant-section.mjs +136 -0
  199. package/src/cli/util/copy.mjs +43 -56
  200. package/src/cli/util/semver.mjs +28 -0
  201. package/src/cli/util/skill-installs.mjs +134 -21
  202. package/src/cli/util/version-preflight.mjs +65 -0
  203. package/templates/aperant-claude-md-appendix.md +37 -0
  204. package/templates/config.json +2 -7
  205. package/workflows/verify-proof.md +8 -3
package/package.json CHANGED
@@ -1,134 +1,134 @@
1
1
  {
2
- "name": "@aperant/framework",
3
- "version": "0.6.7",
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
- "author": "Mikalsen AI <hello@mikalsen.ai>",
6
- "type": "module",
7
- "main": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "bin": {
10
- "framework": "./bin/apt-tools.mjs",
11
- "apt-tools": "./bin/apt-tools.mjs",
12
- "apt-proof-video": "./bin/apt-proof-video.mjs"
13
- },
14
- "exports": {
15
- ".": {
16
- "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js"
18
- },
19
- "./types": {
20
- "types": "./dist/types/index.d.ts",
21
- "import": "./dist/types/index.js"
22
- },
23
- "./cost": {
24
- "types": "./dist/cost/index.d.ts",
25
- "import": "./dist/cost/index.js"
26
- },
27
- "./mappers": {
28
- "types": "./dist/mappers/index.d.ts",
29
- "import": "./dist/mappers/index.js"
30
- },
31
- "./schemas": {
32
- "types": "./dist/schemas/index.d.ts",
33
- "import": "./dist/schemas/index.js"
34
- },
35
- "./standalone": {
36
- "types": "./dist/standalone/index.d.ts",
37
- "import": "./dist/standalone/index.js"
38
- },
39
- "./coordination/event-schema": {
40
- "types": "./src/cli/coordination/event-schema.d.ts",
41
- "import": "./src/cli/coordination/event-schema.mjs"
42
- },
43
- "./roadmap/conductor-view": {
44
- "types": "./src/cli/roadmap/conductor-view.d.ts",
45
- "import": "./src/cli/roadmap/conductor-view.mjs"
46
- },
47
- "./design/scan": {
48
- "import": "./src/cli/design/scan.mjs"
49
- },
50
- "./design/extract-repo": {
51
- "import": "./src/cli/design/extract-repo.mjs"
52
- },
53
- "./design/synthesize": {
54
- "import": "./src/cli/design/synthesize.mjs"
55
- }
56
- },
57
- "files": [
58
- "dist/",
59
- "bin/",
60
- "src/cli/",
61
- "src/cost/",
62
- "commands/",
63
- "skills/",
64
- "agents/",
65
- "prompts/",
66
- "templates/",
67
- "context/",
68
- "workflows/",
69
- "examples/",
70
- "LICENSE",
71
- "README.md",
72
- "CHANGELOG.md",
73
- "!**/__tests__/**",
74
- "!**/*.test.*",
75
- "!**/*.spec.*",
76
- "!**/*.test.d.ts.map",
77
- "!**/*.test.js.map"
78
- ],
79
- "keywords": [
80
- "ai",
81
- "framework",
82
- "coding-assistant",
83
- "claude-code",
84
- "codex",
85
- "aperant"
86
- ],
87
- "license": "AGPL-3.0-only",
88
- "homepage": "https://github.com/Mikalsen-AI/aperant-cloud-desktop/tree/main/packages/framework#readme",
89
- "bugs": {
90
- "url": "https://github.com/Mikalsen-AI/aperant-cloud-desktop/issues"
91
- },
92
- "repository": {
93
- "type": "git",
94
- "url": "https://github.com/Mikalsen-AI/aperant-cloud-desktop.git",
95
- "directory": "packages/framework"
96
- },
97
- "engines": {
98
- "node": ">=18.0.0"
99
- },
100
- "publishConfig": {
101
- "access": "public"
102
- },
103
- "dependencies": {
104
- "@clack/prompts": "^1.2.0",
105
- "proper-lockfile": "^4.1.2",
106
- "yaml": "^2.8.3",
107
- "zod": "^4.3.6"
108
- },
109
- "optionalDependencies": {
110
- "@babel/parser": "^7.29.2",
111
- "@babel/traverse": "^7.29.0",
112
- "@google/genai": "^1.50.1",
113
- "css-tree": "^3.2.1",
114
- "playwright": "^1.59.1"
115
- },
116
- "devDependencies": {
117
- "@vitest/coverage-v8": "^4.1.5"
118
- },
119
- "scripts": {
120
- "build": "tsc && node scripts/extract-personas-schema.mjs",
121
- "dev": "tsc --watch --preserveWatchOutput",
122
- "typecheck": "tsc --noEmit",
123
- "lint": "biome check . --diagnostic-level=error",
124
- "lint:fix": "biome check --write . --diagnostic-level=error",
125
- "clean": "rm -rf dist",
126
- "test": "vitest run",
127
- "c28:cutover": "node scripts/c28-cutover.mjs",
128
- "build-plugin": "node scripts/build-plugin.mjs",
129
- "publish-plugin": "node scripts/publish-plugin.mjs",
130
- "publish:verdaccio": "node scripts/publish-verdaccio.mjs",
131
- "release:verdaccio": "pnpm build && pnpm publish:verdaccio",
132
- "ship:verdaccio": "npm version patch --no-git-tag-version && pnpm build && pnpm publish:verdaccio"
133
- }
134
- }
2
+ "name": "@aperant/framework",
3
+ "version": "0.7.3",
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
+ "author": "Mikalsen AI <hello@mikalsen.ai>",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "framework": "./bin/apt-tools.mjs",
11
+ "apt-tools": "./bin/apt-tools.mjs",
12
+ "apt-proof-video": "./bin/apt-proof-video.mjs"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./types": {
20
+ "types": "./dist/types/index.d.ts",
21
+ "import": "./dist/types/index.js"
22
+ },
23
+ "./cost": {
24
+ "types": "./dist/cost/index.d.ts",
25
+ "import": "./dist/cost/index.js"
26
+ },
27
+ "./mappers": {
28
+ "types": "./dist/mappers/index.d.ts",
29
+ "import": "./dist/mappers/index.js"
30
+ },
31
+ "./schemas": {
32
+ "types": "./dist/schemas/index.d.ts",
33
+ "import": "./dist/schemas/index.js"
34
+ },
35
+ "./standalone": {
36
+ "types": "./dist/standalone/index.d.ts",
37
+ "import": "./dist/standalone/index.js"
38
+ },
39
+ "./coordination/event-schema": {
40
+ "types": "./src/cli/coordination/event-schema.d.ts",
41
+ "import": "./src/cli/coordination/event-schema.mjs"
42
+ },
43
+ "./roadmap/conductor-view": {
44
+ "types": "./src/cli/roadmap/conductor-view.d.ts",
45
+ "import": "./src/cli/roadmap/conductor-view.mjs"
46
+ },
47
+ "./design/scan": {
48
+ "import": "./src/cli/design/scan.mjs"
49
+ },
50
+ "./design/extract-repo": {
51
+ "import": "./src/cli/design/extract-repo.mjs"
52
+ },
53
+ "./design/synthesize": {
54
+ "import": "./src/cli/design/synthesize.mjs"
55
+ }
56
+ },
57
+ "scripts": {
58
+ "build": "tsc && node scripts/extract-personas-schema.mjs",
59
+ "dev": "tsc --watch --preserveWatchOutput",
60
+ "typecheck": "tsc --noEmit",
61
+ "lint": "biome check . --diagnostic-level=error",
62
+ "lint:fix": "biome check --write . --diagnostic-level=error",
63
+ "clean": "rm -rf dist",
64
+ "test": "vitest run",
65
+ "c28:cutover": "node scripts/c28-cutover.mjs",
66
+ "build-plugin": "node scripts/build-plugin.mjs",
67
+ "publish-plugin": "node scripts/publish-plugin.mjs",
68
+ "publish:verdaccio": "node scripts/publish-verdaccio.mjs",
69
+ "release:verdaccio": "pnpm build && pnpm publish:verdaccio",
70
+ "ship:verdaccio": "npm version patch --no-git-tag-version && pnpm build && pnpm publish:verdaccio"
71
+ },
72
+ "files": [
73
+ "dist/",
74
+ "bin/",
75
+ "src/cli/",
76
+ "src/cost/",
77
+ "commands/",
78
+ "skills/",
79
+ "agents/",
80
+ "prompts/",
81
+ "templates/",
82
+ "context/",
83
+ "workflows/",
84
+ "examples/",
85
+ "LICENSE",
86
+ "README.md",
87
+ "CHANGELOG.md",
88
+ "!**/__tests__/**",
89
+ "!**/*.test.*",
90
+ "!**/*.spec.*",
91
+ "!**/*.test.d.ts.map",
92
+ "!**/*.test.js.map"
93
+ ],
94
+ "keywords": [
95
+ "ai",
96
+ "framework",
97
+ "coding-assistant",
98
+ "claude-code",
99
+ "codex",
100
+ "aperant"
101
+ ],
102
+ "license": "AGPL-3.0-only",
103
+ "homepage": "https://github.com/Mikalsen-AI/aperant-cloud-desktop/tree/main/packages/framework#readme",
104
+ "bugs": {
105
+ "url": "https://github.com/Mikalsen-AI/aperant-cloud-desktop/issues"
106
+ },
107
+ "repository": {
108
+ "type": "git",
109
+ "url": "https://github.com/Mikalsen-AI/aperant-cloud-desktop.git",
110
+ "directory": "packages/framework"
111
+ },
112
+ "engines": {
113
+ "node": ">=18.0.0"
114
+ },
115
+ "publishConfig": {
116
+ "access": "public"
117
+ },
118
+ "dependencies": {
119
+ "@clack/prompts": "^1.2.0",
120
+ "proper-lockfile": "^4.1.2",
121
+ "yaml": "^2.8.3",
122
+ "zod": "^4.3.6"
123
+ },
124
+ "optionalDependencies": {
125
+ "@babel/parser": "^7.29.2",
126
+ "@babel/traverse": "^7.29.0",
127
+ "@google/genai": "^1.50.1",
128
+ "css-tree": "^3.2.1",
129
+ "playwright": "^1.59.1"
130
+ },
131
+ "devDependencies": {
132
+ "@vitest/coverage-v8": "^4.1.5"
133
+ }
134
+ }
@@ -0,0 +1,63 @@
1
+ <!-- Conductor Framework Context (auto-injected) -->
2
+ # Aperant framework — slash-skills dispatchable in sub-terminals
3
+
4
+ Dispatch via `sendToTerminal(terminalId, '/<skill> <args>\\r', ...)`.
5
+
6
+ ## Skills
7
+
8
+ | Skill | When to dispatch |
9
+ |-------|------------------|
10
+ | `/apt:author-skill` | Author a new Aperant skill (test-first stub). |
11
+ | `/apt:bootstrap` | Generate / refresh PROJECT.md. |
12
+ | `/apt:close-task` | Post-merge: confirm PR merged, flip phase, GC state. |
13
+ | `/apt:create-docs` | Persona-first product docs from PROJECT.md + features. |
14
+ | `/apt:debug` | Systematic debugging with persistent state. |
15
+ | `/apt:design` | DESIGN.md + wireframe + critique. Hands off to apt:plan. |
16
+ | `/apt:diagram` | .excalidraw / MCP-canvas diagrams. |
17
+ | `/apt:discuss` | Brainstorm vision or lock ambiguous decisions. |
18
+ | `/apt:docs` | Generate / update documentation verified against code. |
19
+ | `/apt:execute` | Execute an implementation plan — build code from subtasks. |
20
+ | `/apt:improve` | Proactive refactor via DEEPENING / INTERFACE / LANGUAGE lenses. |
21
+ | `/apt:mockup` | HTML+Tailwind mockup loop with parallel variants. |
22
+ | `/apt:pause` | Human-initiated session handoff. |
23
+ | `/apt:personas` | Discover 3-5 personas grounded in code + PROJECT.md. |
24
+ | `/apt:plan` | Create an implementation plan from a task description. |
25
+ | `/apt:pr-review` | Multi-agent PR review (6 specialists, validator, fixer). |
26
+ | `/apt:prototype` | Question-driven throwaway prototyping. |
27
+ | `/apt:quick` | Fast task execution — skip planning. |
28
+ | `/apt:release-notes` | Persona-aware user-facing release notes. |
29
+ | `/apt:resume` | Restore context from paused session / crash. |
30
+ | `/apt:review` | Task-level code review (6-pass fix-all pipeline). |
31
+ | `/apt:roadmap` | Manage per-scope roadmaps (milestones, phases). |
32
+ | `/apt:roundtable` | 10-agent structured debate w/ supermajority vote. |
33
+ | `/apt:run` | Full pipeline — plan/execute/verify/review. |
34
+ | `/apt:scan` | Build/refresh the .aperant/features/ registry. |
35
+ | `/apt:setup` | Configure Aperant preferences. |
36
+ | `/apt:ship` | Open PR with QA scores + decision traceability. |
37
+ | `/apt:spar` | Adversarial sparring loop between two CLIs (max 3 rounds). |
38
+ | `/apt:stress-test` | Scenario simulation to catch plan gaps. |
39
+ | `/apt:terminal` | Spawn a sibling Aperant terminal w/ its own worktree. |
40
+ | `/apt:triage` | Move a task through the 5-state triage machine. |
41
+ | `/apt:update` | Refresh installed skills/agents/hooks across runtimes. |
42
+ | `/apt:verify` | Validate implementation against spec (QA review loop). |
43
+ | `/apt:verify-proof` | Visual proof-of-work verification (screenshots, BETA). |
44
+ | `/apt:watch-ci` | Post-ship CI watcher (poll, auto-fix red, push). |
45
+ | `/apt:zoom-out` | Orient yourself in an unfamiliar area — one-page summary. |
46
+
47
+ ## Dispatch recipe
48
+
49
+ Spawn a Claude Code CLI in a fresh terminal, then send the slash:
50
+
51
+ ```
52
+ spawnTerminal({ projectPath, cwd, cliCommand: 'claude --dangerously-skip-permissions', ... })
53
+ sendToTerminal(terminalId, '/apt:plan <terse task description>\r', ...)
54
+ ```
55
+
56
+ Codex / Gemini / OpenCode ports exist — swap `cliCommand` accordingly.
57
+ Skill semantics are identical across CLIs.
58
+
59
+ ## Observe-then-act
60
+
61
+ Read what a sub-terminal produced via `readFromTerminal(terminalId,
62
+ {tailBytes?})`. Use AFTER a write to confirm the skill took. NEVER assume
63
+ the write landed — observe.
@@ -97,10 +97,21 @@ Write (use when needed, no human approval gating):
97
97
  - `listTerminals()` — fleet snapshot (cwd, busyState, isCLIMode).
98
98
  - `sendToTerminal(terminalId, input, requestId, reasoning)` — tap-on-
99
99
  shoulder. Always one line. Append `\r` to submit. NEVER multi-line essay.
100
+ - `readFromTerminal(terminalId, {tailBytes?})` — snapshot recent PTY
101
+ output (~100 KB cap). Use AFTER `sendToTerminal` to confirm the write
102
+ took. NEVER assume — observe. On self-hosted web / cloud the host may
103
+ return `{output: null, error: 'host not action-capable in this mode'}`;
104
+ fall back to `readEventLog` polling there.
100
105
  - `destroyTerminal(terminalId, requestId, reasoning)` — irreversible.
101
106
  Prefer graceful `sendToTerminal('exit\r')`.
102
107
  - `emitIntent({...})` — audit envelope for non-tool decisions.
103
108
 
109
+ ## Framework knowledge
110
+
111
+ The auto-injected `conductor-framework-context` block at the very top of
112
+ this system prompt lists every `/apt:*` skill you can dispatch into a
113
+ sub-terminal. Consult it BEFORE deciding which skill to send.
114
+
104
115
  Tool surface depends on host. If `spawnTerminal` is not in your tools,
105
116
  you are in observe-only mode — do not promise spawns; describe what you
106
117
  WOULD do.
@@ -40,6 +40,7 @@ Confirm a shipped PR has merged on GitHub, then run the closer side of the task
40
40
  - `.aperant/events/{today}.jsonl` — emits `task.closed.merged`.
41
41
  - `.aperant/config.json` — strips `authorship_overrides['pr-{N}']` entries for merged PRs.
42
42
  - `.aperant/roadmap/{scope}/**` — linked-phase flip (when `task_isolation.auto_close_phase: true`).
43
+ - `.aperant/ci-watches/{pr}.json` — removed for each merged PR (BUG-027 (b) side-effect: prevents watcher state files leaking past PR-terminal-state). Idempotent — already-removed state is a no-op. For retroactive cleanup of orphan state files left behind by pre-fix runs, use `apt-tools ci-watch sweep . --orphaned`.
43
44
  </state_files>
44
45
 
45
46
  <process>
@@ -123,6 +124,8 @@ close-merged emits an envelope with:
123
124
 
124
125
  Report the summary verbatim. If anything landed in `skipped[]` with a recoverable reason (`offline`, `rate_limited`), suggest the user re-run once the network clears.
125
126
 
127
+ **Local cleanup recap (best-effort).** On confirmed merge, `task close-merged` runs `computeWorktreeCleanup` against the primary repo (`packages/framework/src/cli/task/worktree-cleanup.mjs:140-230`): `git fetch origin <base>` (failure → recorded as `fetch_failed` warning, cleanup proceeds), `git checkout <base>` (failure → returns `action: 'checkout_failed'` and preserves BOTH the worktree and the task branch — nothing is removed), `git merge --ff-only origin/<base>` (failure → `ff_only_failed` warning, GC still runs), `git worktree remove <wtPath>`, and `git branch -d <taskBranch>` (failure on squash/rebase merges → `branch_delete_failed` warning, `branch_deleted: false` in the envelope; user can `git branch -D` manually). This is why `/apt:watch-ci` auto-merge MUST NOT pass `gh pr merge --delete-branch` — that flag would try to do the same work from inside the worktree where `git switch <base>` cannot succeed (see FRAMEWORK-BUG-019).
128
+
126
129
  ## 4. Narrate-only mode
127
130
 
128
131
  When invoked with `--narrate-only`, skip §1 (no `gh pr view` polling) and §2 (no destructive close path). The deterministic close already ran via the passive post-merge sweep — your job is to drain the `state.pending_narration[]` ledger the sweep parked.
@@ -133,10 +136,13 @@ Flags:
133
136
 
134
137
  Per ledger entry `{ task_id, scope, phase_id, closed_at, pr_number }`:
135
138
 
139
+ 0. **Enumerate the ledger first.** Run `apt-tools task close-merged . --narrate-only [--task <id>]`. The envelope's `closed[]` is the read-only list of pending narration rows (each carries `narration_pending: true`); state.json is not mutated. When `closed[]` is empty, exit early with `{status: 'ok', narrated: [], skipped: [], remaining: 0}` — there is nothing to drain.
136
140
  1. Run `apt-tools features-audit . --apply-stubs --task <task_id>` so the feature registry catches whatever the closed task introduced. If the subprocess exits non-zero, skip the entry with `reason: 'features-audit-failed'` — never block narration on registry update.
137
141
  2. When `phase_id` is non-null, spawn `apt-team-docs-narrator` (background, fire-and-forget) using the same shape as §2.5: `subagent_type: apt-team-docs-narrator`, `run_in_background: true`, `description: Narrate shipped phase {phase_id}`, `prompt: Run in phase-ship mode with --phase {phase_id} --scope {scope}.`. When `phase_id` is null, skip the spawn with `reason: 'no-phase-id'` (quick tasks have no phase to narrate).
138
142
  3. On successful spawn (or successful no-phase skip), drain the row via `apt-tools task narration-drain . --task <task_id>` which acquires `withFileLock(state.json)` and removes the matching `pending_narration[]` entry. On spawn failure, leave the row in place with `reason: 'narrator-spawn-failed'` so the user can re-invoke.
139
143
 
144
+ **At-least-once retry semantics (FRAMEWORK-BUG-020).** Step 0 is read-only — it does NOT remove rows. Steps 1–3 are the existing per-row drain contract: a row stays in `pending_narration[]` until step 3 calls `narration-drain` successfully. If the orchestrator crashes between step 2 (narrator spawn) and step 3 (drain), the row remains parked and a retry will spawn narration again. Re-spawning is safe because the narrator is **anchor-replace idempotent** by design (see `agents/apt-team-docs-narrator.md` §6 / §2 and the "Idempotent operations only" rule in §notes) — it uses HTML-comment anchors to bound the replaced region in ROADMAP.md, so a second run replaces the same span rather than appending.
145
+
140
146
  Emit a summary envelope:
141
147
 
142
148
  ```json
@@ -17,7 +17,7 @@ execution_modes:
17
17
  - step
18
18
  - research
19
19
  allowed-tools: "Bash, Read, Grep, Glob, Write"
20
- argument-hint: "apt:discuss [--brainstorm] [topic]"
20
+ argument-hint: "apt:discuss [--brainstorm] [--grill] [topic]"
21
21
  gates: []
22
22
  ---
23
23
  <objective>
@@ -183,10 +183,11 @@ If any file is missing, proceed with what's available. The framework works with
183
183
  Extract the task description from `$ARGUMENTS`:
184
184
 
185
185
  1. Strip mode flags (`--assumptions`, `--power`, `--auto`, `--review-auto`, `--continue`) from arguments
186
- 2. The remaining text is the task description
187
- 3. If task description is empty but `state.json` has an `active_task`, use that task's description
188
- 4. If still empty, ask: "What are you working on?"
189
- 5. Generate a `task-id` slug from the description: lowercase, hyphens, max 40 characters
186
+ 2. Strip the **`--grill`** overlay flag from arguments (orthogonal to the mode flags — see Section 6.5). `--grill` may combine with any mode; standalone `--grill` defaults to Interactive.
187
+ 3. The remaining text is the task description
188
+ 4. If task description is empty but `state.json` has an `active_task`, use that task's description
189
+ 5. If still empty, ask: "What are you working on?"
190
+ 6. Generate a `task-id` slug from the description: lowercase, hyphens, max 40 characters
190
191
  - Example: "Add OAuth login with Google" -> `add-oauth-login-with-google`
191
192
 
192
193
  ## 3.5. Brainstorm (skip if you picked decision-lock in Section 1)
@@ -564,6 +565,47 @@ Review-Auto is Auto Mode **plus one human checkpoint at the batch end**. It does
564
565
 
565
566
  Do NOT introduce per-decision staging ("show me D-01, wait, show me D-02, wait...") — that collapses review-auto into spaced interactive mode and defeats the point of joint reasoning up front. Do NOT skip the pause ("autonomy is high, let's just write it") — that collapses review-auto into auto. The one pause at the end is the whole identity of this mode.
566
567
 
568
+ ## 6.5. Grill Mode (`--grill` flag — Pocock `grill-with-docs` overlay)
569
+
570
+ **Activate when:** the user invoked the skill with `--grill`. This is an **overlay**, not a mode — it stacks on top of whichever Section 6 mode is active (Interactive by default; combine with `--auto` etc. as desired). The overlay does two things: (1) it applies Pocock's 4 grill moves during decision resolution; (2) it fires inline writes to CONTEXT.md and ADRs as terms resolve and decisions pass the Nygard 3-gate.
571
+
572
+ The discipline this overlay loads is already in [`appendices/grill-discipline.md`](./appendices/grill-discipline.md) — re-read the reframe sentence and the autonomy degradation table before each grill turn. **Do NOT duplicate that content here.** What follows is only the moves + writer-call instructions specific to the overlay.
573
+
574
+ ### The 4 grill moves (apply during gray-area resolution)
575
+
576
+ 1. **Challenge against the glossary.** When the user uses a term that conflicts with an existing CONTEXT.md term-block, call it out immediately: *"Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"* Read `CONTEXT.md` (or per-context CONTEXT files via `CONTEXT-MAP.md`) when the overlay activates; skip silently if absent.
577
+ 2. **Sharpen fuzzy language.** When the user uses vague or overloaded terms, propose a precise canonical term: *"You're saying 'account' — do you mean Customer or User? Those are different things."*
578
+ 3. **Stress-test with concrete scenarios.** When domain relationships are being discussed, invent specific scenarios that probe edge cases and force precision about the boundaries between concepts.
579
+ 4. **Cross-reference with code.** When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: *"Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"*
580
+
581
+ ### Inline writer calls (NOT batched)
582
+
583
+ When a term resolves with confidence during the grill, invoke `apt-tools context write` to upsert the term-block into CONTEXT.md **right there** — do NOT batch:
584
+
585
+ ```bash
586
+ node .aperant/deps/node_modules/@aperant/framework/bin/apt-tools.mjs context write . \
587
+ --term "Plan thread" \
588
+ --definition "<one-line definition>" \
589
+ --aliases-to-avoid "Plan session,plan chat" \
590
+ --cardinality "one-to-many"
591
+ ```
592
+
593
+ **Lazy creation:** if no `CONTEXT.md` exists at the project root (or in the relevant per-context directory when `CONTEXT-MAP.md` is present), the first resolved term creates the file. Do NOT create CONTEXT.md upfront with placeholder content.
594
+
595
+ **Glossary-only rule:** CONTEXT.md is a glossary of domain terms — NO implementation details, NO spec content, NO scratch-pad notes. Implementation lives in `spec.md` / `implementation_plan.json`; scratch lives in `.aperant/context/notes/{task-id}.md`. Term-blocks are user-facing concepts (e.g. "Plan thread", "Sparring round"), not code identifiers (e.g. "ChatSession", "useTaskStore").
596
+
597
+ When a decision passes the **Nygard 3-gate**, offer to write an ADR via `apt-tools adr write .`. The 3-gate (ALL three must hold — miss one and skip the ADR):
598
+
599
+ 1. **Hard to reverse** — the cost of changing your mind later is meaningful.
600
+ 2. **Surprising without context** — a future reader will wonder *"why did they do it this way?"*.
601
+ 3. **Result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons.
602
+
603
+ If only one or two hold, the decision belongs in `.aperant/context/notes/{task-id}.md` (locked-decisions list), not in an ADR.
604
+
605
+ ### Autonomy interaction
606
+
607
+ `--grill` does not change the autonomy degradation already specified in [`appendices/grill-discipline.md`](./appendices/grill-discipline.md). Autonomy 1 grills every term/decision interactively; Autonomy 2 batches recommendations; Autonomy 3 auto-locks with the three escalation triggers (conflict-with-locked, critical-path file, no-defensible-default). The overlay simply ensures that whichever autonomy path runs, the writer CLIs fire as side-effects of the resolution work.
608
+
567
609
  ## 7. Advanced Elicitation (DEEP Tasks Only)
568
610
 
569
611
  After all decisions are locked, check the task track. If the track is DEEP (from state.json or router context), behavior depends on the resolved mode from Section 6's precedence chain (D-07):
@@ -383,11 +383,20 @@ executor commits introduce a new feature surface without registering it.
383
383
 
384
384
  ```bash
385
385
  node packages/framework/bin/apt-tools.mjs features-audit . \
386
+ --task-id "$TASK_ID" \
386
387
  --diff-files "$(git diff --name-only HEAD^ HEAD | tr '\n' ',')" \
387
388
  --apply-stubs
388
389
  ```
389
390
 
390
391
  Notes:
392
+ - `--task-id $TASK_ID` (BUG-025b) is mandatory when the executor runs
393
+ from the main-repo cwd instead of inside the worktree (the
394
+ orchestrator's common path). features-audit resolves the worktree's
395
+ `.aperant/features/` from the active task record and writes there,
396
+ preventing generated `*.json` from leaking into main. When invoked
397
+ from the worktree cwd directly, `--task-id` is a no-op (layer 1
398
+ detection short-circuits). Pass `--no-worktree-redirect` only when
399
+ you intentionally want to write to the invoking cwd.
391
400
  - `--apply-stubs` only runs when the matched surface's policy is
392
401
  `auto-update` (the default for `.aperant/features/*.json`). Users who
393
402
  opted out via `/apt:setup` Batch 7 get a no-op — the command still
@@ -99,6 +99,18 @@ For STANDARD and COMPLEX tasks:
99
99
  - Test files that will need updates
100
100
  - Configuration that may need changes
101
101
 
102
+ ### 4.4. React state guidance — sync-store vs render-committed ref (BUG-025-planner)
103
+
104
+ When a planned event handler fires a flush/persist immediately after mutating a Zustand/Jotai/refs-stored store, the spec MUST recommend reading from `store.getState()` (or the equivalent direct-read primitive) on the synchronous path, NOT from a `useRef`-populated-by-`useEffect`.
105
+
106
+ Why: refs populated via `useEffect` lag the store by exactly one render cycle. A handler that mutates the store and immediately reads the ref sees the pre-mutation value, silently corrupting persists and order-of-operations contracts. Reference pattern: `apps/desktop/src/renderer/src/App.tsx::runUpsertForIds` (post-fix commit `4c263856`).
107
+
108
+ Investigation checklist when the task touches a Zustand/Jotai store or any handler that does flush-after-mutate:
109
+
110
+ - Grep for `useRef(` references that cache store state (e.g. `const fooRef = useRef(foo)` populated by `useEffect(() => { fooRef.current = foo }, [foo])`).
111
+ - If the spec or planned subtasks read from such a ref on a synchronous path that ALSO mutates the store, recommend `store.getState()` (or `useFooStore.getState()`) as the read primitive.
112
+ - Note the caveat explicitly in the spec's Implementation Decisions section so the executor doesn't silently revert it.
113
+
102
114
  ### 4.5. Consume design.md (C24)
103
115
 
104
116
  If `{task_dir}/design.md` exists (emitted by a prior `/apt:design` run), load it before decomposing subtasks:
@@ -257,7 +257,7 @@ When the result is `unknown`, treat it as `external` for safety and prompt the u
257
257
  Authorship could not be auto-detected for PR #${PR_NUMBER}. Treat as [owned / external]? (default: external)
258
258
  ```
259
259
 
260
- If `autonomy_level >= 3` (yolo), skip the prompt and lock in `external`. Persist the user's answer to BOTH `pr-state.json:authorship` AND `config.json:pr_review.authorship_overrides['pr-${PR_NUMBER}']` so subsequent rounds don't re-ask.
260
+ If `autonomy_level >= 3` (yolo), skip the prompt and lock in `external`. Persist the user's answer to `pr-state.json:authorship` so subsequent rounds don't re-ask. (Per C56 A3 — authorship overrides moved from `config.json:pr_review.authorship_overrides` to per-PR `pr-state.json` so they GC with the pr-review round. Legacy `config.json` entries are still read with a deprecation warning + auto-promoted to pr-state on next `init-pr`; do NOT write to `config.json` from new code.)
261
261
 
262
262
  Store the result as `AUTHORSHIP_MODE` and use it as a gate at every later phase:
263
263
 
@@ -1195,6 +1195,12 @@ Take all confirmed, fixable findings and group them into up to 3 independent gro
1195
1195
 
1196
1196
  #### Step 3: Spawn Fix Agents
1197
1197
 
1198
+ **Capture the iteration-start SHA BEFORE spawning fixers** (used by both the Step 4b audit gate AND the per-fixer Pre-Return Self-Audit added in BUG-016 — fixers now commit atomically per finding, and the audit window is scoped by this SHA):
1199
+
1200
+ ```bash
1201
+ ITERATION_START_SHA=$(cd "${WORKTREE_PATH}" && git rev-parse HEAD)
1202
+ ```
1203
+
1198
1204
  For each fix group, spawn a fix agent. Read the agent definition from `.claude/agents/apt-pr-review-fixer.md` and fill in:
1199
1205
 
1200
1206
  | Placeholder | Value |
@@ -1207,6 +1213,7 @@ For each fix group, spawn a fix agent. Read the agent definition from `.claude/a
1207
1213
  | `[CRITICAL_APPROVAL]` | `true` or `false` for each critical finding in this group |
1208
1214
  | `[PARALLEL_FIXERS]` | `true` if more than 1 fixer is spawned this iteration |
1209
1215
  | `[WORKTREE_PATH]` | The worktree path — fix agents edit files HERE, not in the user's working directory |
1216
+ | `[ITERATION_START_SHA]` | The SHA captured BEFORE spawning fixers (see Step 4b's `ITERATION_START_SHA=$(...)` capture). Required for BUG-016 commit-discipline Pre-Return Self-Audit. |
1210
1217
 
1211
1218
  ```
1212
1219
  Agent(
@@ -1260,7 +1267,9 @@ If `--since-sha` is **omitted**, the CLI falls back to `git merge-base HEAD orig
1260
1267
 
1261
1268
  Rule of thumb: pass `--since-sha "${ITERATION_START_SHA}"` on every audit invocation. The merge-base fallback exists only so a missing flag doesn't flip every standard-branch-workflow repo into a false-positive hallucination — it is NOT a replacement for the explicit flag.
1262
1269
 
1263
- The CLI returns a JSON envelope with `verdict` ∈ `verified | hallucinated | skipped`, writes `iterations/${ITERATION}/audit.json` (append-only), and bumps `metadata.json.fixer_hallucinations_total` on every `hallucinated` outcome. The envelope's `observed.since_sha` + `observed.since_sha_source` fields record which SHA was used and where it came from (`flag` | `merge-base` | `null`). The same envelope is used for the fixer and the self-reviewer (Phase 7) — `--fixer self-reviewer` reads from `self-review.md` instead of `fixes-applied-group{N}.md`.
1270
+ The CLI returns a JSON envelope with `verdict` ∈ `verified | hallucinated | skipped`, writes `iterations/${ITERATION}/audit.json` (append-only), and bumps `metadata.json.fixer_hallucinations_total` on every `hallucinated` outcome. The envelope's `observed.since_sha` + `observed.since_sha_source` fields record which SHA was used and where it came from (`flag` | `merge-base` | `null`). The same envelope is used for the fixer and the self-reviewer (Phase 7) — `--fixer self-reviewer` reads from `self-review.md`.
1271
+
1272
+ **Canonical fix-report filename per fixer (BUG-030):** each fixer agent writes to `fixes-applied-${FIXER_NAME}.md` (e.g. `fixes-applied-fixer-1.md`). The audit CLI resolves candidates in strict order: `fixes-applied-group{N}.md` (legacy group-named, pre-BUG-030 reviews) → `fixes-applied-fixer-{N}.md` (NEW fixer-named) → `fixes-applied-${FIXER_NAME}.md` (exact match, preferred for non-numeric fixer names) → `fixes-applied.md` (legacy unscoped, single-fixer reviews only). Writing the canonical name eliminates the cross-fixer false-positive `hallucinated` verdict that fired when two parallel fixers shared `fixes-applied.md`.
1264
1273
 
1265
1274
  | Verdict | Orchestrator Action |
1266
1275
  |---------|---------------------|
@@ -279,18 +279,29 @@ skill MUST exit silently regardless of the config value, so spawned subagents
279
279
  never block on a prompt that no human will answer.
280
280
 
281
281
  ```bash
282
- # Pseudocode the model executes inline:
282
+ # Pseudocode the model executes inline.
283
+ # AUDIT-001: `preferences.quick_task_post_verify` is per-device — read from
284
+ # the MERGED config (shared `.aperant/config.json` + local
285
+ # `.aperant/config.local.json`). Local wins on collision. Reading raw
286
+ # `config.json` only would miss per-device overrides.
283
287
  node -e '
284
288
  const fs = require("fs");
285
289
  const path = require("path");
286
- const cfgPath = path.join(process.cwd(), ".aperant/config.json");
290
+ const readJsonOrEmpty = (p) => { try { return JSON.parse(fs.readFileSync(p, "utf-8")) ?? {} } catch { return {} } };
291
+ const shared = readJsonOrEmpty(path.join(process.cwd(), ".aperant/config.json"));
292
+ const local = readJsonOrEmpty(path.join(process.cwd(), ".aperant/config.local.json"));
293
+ function merge(a, b) {
294
+ if (a === null || typeof a !== "object" || Array.isArray(a)) return b;
295
+ if (b === null || typeof b !== "object" || Array.isArray(b)) return b;
296
+ const out = { ...a };
297
+ for (const k of Object.keys(b)) out[k] = (k in a) ? merge(a[k], b[k]) : b[k];
298
+ return out;
299
+ }
300
+ const cfg = merge(shared, local);
287
301
  let mode = "ask";
288
- try {
289
- const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
290
- if (cfg && cfg.preferences && cfg.preferences.quick_task_post_verify) {
291
- mode = cfg.preferences.quick_task_post_verify;
292
- }
293
- } catch {}
302
+ if (cfg.preferences && cfg.preferences.quick_task_post_verify) {
303
+ mode = cfg.preferences.quick_task_post_verify;
304
+ }
294
305
  if (mode === "never" || !process.stdin.isTTY) process.exit(0);
295
306
  if (mode === "always") { /* invoke apt:verify {task-id} */ process.exit(0); }
296
307
  // mode === "ask": readline prompt with 30s timeout, default = skip.
@@ -41,6 +41,7 @@ Parse the investigation query. Identify:
41
41
  3. Read key files to understand the full picture
42
42
  4. Follow import chains to map dependencies
43
43
  5. Check tests for behavioral documentation
44
+ 6. **Report which refs cache store state on a render-cycle delay** (BUG-025-planner): when investigating React state or any Zustand/Jotai store touched by handlers, grep for `useRef(` patterns populated via `useEffect`. Flag them explicitly — they lag the store by one render and any sync-mutate-then-read code path against them silently corrupts. Reference pattern: `apps/desktop/src/renderer/src/App.tsx::runUpsertForIds` (post-fix commit `4c263856`).
44
45
 
45
46
  ## 3. Report Findings
46
47
  Produce a clear, structured answer: