@aperant/framework 0.17.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/agents/apt-executor.md +6 -0
  3. package/agents/apt-planner.md +3 -2
  4. package/bin/features-reconcile-check.mjs +77 -0
  5. package/dist/cli/artifacts/self-stage.d.mts.map +1 -1
  6. package/dist/cli/artifacts/self-stage.mjs +2 -1
  7. package/dist/cli/artifacts/self-stage.mjs.map +1 -1
  8. package/dist/cli/cli-wrappers/features-reconcile.d.mts +2 -0
  9. package/dist/cli/cli-wrappers/features-reconcile.d.mts.map +1 -0
  10. package/dist/cli/cli-wrappers/features-reconcile.mjs +9 -0
  11. package/dist/cli/cli-wrappers/features-reconcile.mjs.map +1 -0
  12. package/dist/cli/commands/ci-watch.mjs +49 -2
  13. package/dist/cli/commands/ci-watch.mjs.map +1 -1
  14. package/dist/cli/commands/commit.mjs +3 -3
  15. package/dist/cli/commands/commit.mjs.map +1 -1
  16. package/dist/cli/commands/event.mjs +16 -16
  17. package/dist/cli/commands/event.mjs.map +1 -1
  18. package/dist/cli/commands/features-reconcile.d.mts +2 -0
  19. package/dist/cli/commands/features-reconcile.d.mts.map +1 -0
  20. package/dist/cli/commands/features-reconcile.mjs +143 -0
  21. package/dist/cli/commands/features-reconcile.mjs.map +1 -0
  22. package/dist/cli/commands/health-check.d.mts +2 -2
  23. package/dist/cli/commands/health-check.mjs +2 -2
  24. package/dist/cli/commands/merge-integrate.mjs +3 -3
  25. package/dist/cli/commands/merge-integrate.mjs.map +1 -1
  26. package/dist/cli/commands/produce.d.mts +9 -0
  27. package/dist/cli/commands/produce.d.mts.map +1 -0
  28. package/dist/cli/commands/produce.mjs +1345 -0
  29. package/dist/cli/commands/produce.mjs.map +1 -0
  30. package/dist/cli/commands/task.d.mts +16 -1
  31. package/dist/cli/commands/task.d.mts.map +1 -1
  32. package/dist/cli/commands/task.mjs +434 -266
  33. package/dist/cli/commands/task.mjs.map +1 -1
  34. package/dist/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
  35. package/dist/cli/coordination/auto-emit-artifact-ready.mjs.map +1 -1
  36. package/dist/cli/coordination/event-schema.d.mts +5 -3
  37. package/dist/cli/coordination/event-schema.d.mts.map +1 -1
  38. package/dist/cli/coordination/event-schema.mjs +245 -21
  39. package/dist/cli/coordination/event-schema.mjs.map +1 -1
  40. package/dist/cli/coordination/store.d.mts +2 -2
  41. package/dist/cli/coordination/store.mjs +4 -4
  42. package/dist/cli/coordination/store.mjs.map +1 -1
  43. package/dist/cli/dispatch.d.mts.map +1 -1
  44. package/dist/cli/dispatch.mjs +4 -2
  45. package/dist/cli/dispatch.mjs.map +1 -1
  46. package/dist/cli/features/area-shape.d.mts +11 -0
  47. package/dist/cli/features/area-shape.d.mts.map +1 -0
  48. package/dist/cli/features/area-shape.mjs +141 -0
  49. package/dist/cli/features/area-shape.mjs.map +1 -0
  50. package/dist/cli/features/delta.d.mts +78 -0
  51. package/dist/cli/features/delta.d.mts.map +1 -0
  52. package/dist/cli/features/delta.mjs +591 -0
  53. package/dist/cli/features/delta.mjs.map +1 -0
  54. package/dist/cli/features/reconcile.d.mts +236 -0
  55. package/dist/cli/features/reconcile.d.mts.map +1 -0
  56. package/dist/cli/features/reconcile.mjs +1126 -0
  57. package/dist/cli/features/reconcile.mjs.map +1 -0
  58. package/dist/cli/features/surface-map.d.mts +63 -0
  59. package/dist/cli/features/surface-map.d.mts.map +1 -0
  60. package/dist/cli/features/surface-map.mjs +191 -0
  61. package/dist/cli/features/surface-map.mjs.map +1 -0
  62. package/dist/cli/{commands/features-audit.d.mts → features/write-root.d.mts} +4 -3
  63. package/dist/cli/features/write-root.d.mts.map +1 -0
  64. package/dist/cli/features/write-root.mjs +137 -0
  65. package/dist/cli/features/write-root.mjs.map +1 -0
  66. package/dist/cli/gate/gates/features-reconciled.d.mts +36 -0
  67. package/dist/cli/gate/gates/features-reconciled.d.mts.map +1 -0
  68. package/dist/cli/gate/gates/features-reconciled.mjs +67 -0
  69. package/dist/cli/gate/gates/features-reconciled.mjs.map +1 -0
  70. package/dist/cli/gate/gates/index.mjs +1 -0
  71. package/dist/cli/gate/gates/index.mjs.map +1 -1
  72. package/dist/cli/help.d.mts.map +1 -1
  73. package/dist/cli/help.mjs +31 -1
  74. package/dist/cli/help.mjs.map +1 -1
  75. package/dist/cli/install/legacy-paths.d.mts.map +1 -1
  76. package/dist/cli/install/legacy-paths.mjs +2 -0
  77. package/dist/cli/install/legacy-paths.mjs.map +1 -1
  78. package/dist/cli/produce/blind-probe.d.mts +85 -0
  79. package/dist/cli/produce/blind-probe.d.mts.map +1 -0
  80. package/dist/cli/produce/blind-probe.mjs +217 -0
  81. package/dist/cli/produce/blind-probe.mjs.map +1 -0
  82. package/dist/cli/produce/claim.d.mts +188 -0
  83. package/dist/cli/produce/claim.d.mts.map +1 -0
  84. package/dist/cli/produce/claim.mjs +518 -0
  85. package/dist/cli/produce/claim.mjs.map +1 -0
  86. package/dist/cli/produce/done-gate.d.mts +87 -0
  87. package/dist/cli/produce/done-gate.d.mts.map +1 -0
  88. package/dist/cli/produce/done-gate.mjs +200 -0
  89. package/dist/cli/produce/done-gate.mjs.map +1 -0
  90. package/dist/cli/produce/events.d.mts +77 -0
  91. package/dist/cli/produce/events.d.mts.map +1 -0
  92. package/dist/cli/produce/events.mjs +126 -0
  93. package/dist/cli/produce/events.mjs.map +1 -0
  94. package/dist/cli/produce/evidence-oracle.d.mts +63 -0
  95. package/dist/cli/produce/evidence-oracle.d.mts.map +1 -0
  96. package/dist/cli/produce/evidence-oracle.mjs +122 -0
  97. package/dist/cli/produce/evidence-oracle.mjs.map +1 -0
  98. package/dist/cli/produce/ledger.d.mts +140 -0
  99. package/dist/cli/produce/ledger.d.mts.map +1 -0
  100. package/dist/cli/produce/ledger.mjs +272 -0
  101. package/dist/cli/produce/ledger.mjs.map +1 -0
  102. package/dist/cli/produce/probe-family.d.mts +53 -0
  103. package/dist/cli/produce/probe-family.d.mts.map +1 -0
  104. package/dist/cli/produce/probe-family.mjs +160 -0
  105. package/dist/cli/produce/probe-family.mjs.map +1 -0
  106. package/dist/cli/produce/projection.d.mts +55 -0
  107. package/dist/cli/produce/projection.d.mts.map +1 -0
  108. package/dist/cli/produce/projection.mjs +97 -0
  109. package/dist/cli/produce/projection.mjs.map +1 -0
  110. package/dist/cli/produce/run-id.d.mts +42 -0
  111. package/dist/cli/produce/run-id.d.mts.map +1 -0
  112. package/dist/cli/produce/run-id.mjs +79 -0
  113. package/dist/cli/produce/run-id.mjs.map +1 -0
  114. package/dist/cli/produce/saga.d.mts +180 -0
  115. package/dist/cli/produce/saga.d.mts.map +1 -0
  116. package/dist/cli/produce/saga.mjs +290 -0
  117. package/dist/cli/produce/saga.mjs.map +1 -0
  118. package/dist/cli/produce/scheduler.d.mts +165 -0
  119. package/dist/cli/produce/scheduler.d.mts.map +1 -0
  120. package/dist/cli/produce/scheduler.mjs +399 -0
  121. package/dist/cli/produce/scheduler.mjs.map +1 -0
  122. package/dist/cli/produce/setpoint.d.mts +52 -0
  123. package/dist/cli/produce/setpoint.d.mts.map +1 -0
  124. package/dist/cli/produce/setpoint.mjs +113 -0
  125. package/dist/cli/produce/setpoint.mjs.map +1 -0
  126. package/dist/cli/produce/verification-ttl.d.mts +75 -0
  127. package/dist/cli/produce/verification-ttl.d.mts.map +1 -0
  128. package/dist/cli/produce/verification-ttl.mjs +169 -0
  129. package/dist/cli/produce/verification-ttl.mjs.map +1 -0
  130. package/dist/cli/release-notes/ship-autodraft.mjs +2 -2
  131. package/dist/cli/roadmap/{conductor-view.d.mts → showrunner-view.d.mts} +3 -3
  132. package/dist/cli/roadmap/showrunner-view.d.mts.map +1 -0
  133. package/dist/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +7 -7
  134. package/dist/cli/roadmap/showrunner-view.mjs.map +1 -0
  135. package/dist/cli/variant/gallery.d.mts.map +1 -1
  136. package/dist/cli/variant/gallery.mjs +7 -3
  137. package/dist/cli/variant/gallery.mjs.map +1 -1
  138. package/dist/plugin/.claude-plugin/plugin.json +2 -1
  139. package/dist/plugin/agents/apt-executor.md +6 -0
  140. package/dist/plugin/agents/apt-planner.md +3 -2
  141. package/dist/plugin/skills/apt/SKILL.md +112 -38
  142. package/dist/plugin/skills/apt-close-task/SKILL.md +2 -2
  143. package/dist/plugin/skills/apt-debug/SKILL.md +22 -24
  144. package/dist/plugin/skills/apt-execute/SKILL.md +35 -26
  145. package/dist/plugin/skills/apt-fan-out/SKILL.md +4 -4
  146. package/dist/plugin/skills/apt-handoff/SKILL.md +1 -1
  147. package/dist/plugin/skills/apt-mockup/SKILL.md +1 -1
  148. package/dist/plugin/skills/apt-plan/SKILL.md +5 -5
  149. package/dist/plugin/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
  150. package/dist/plugin/skills/apt-produce/SKILL.md +606 -0
  151. package/dist/plugin/skills/apt-quick/SKILL.md +27 -33
  152. package/dist/plugin/skills/apt-review/SKILL.md +14 -11
  153. package/dist/plugin/skills/apt-run/SKILL.md +132 -3
  154. package/dist/plugin/skills/apt-ship/SKILL.md +29 -5
  155. package/dist/plugin/skills/apt-spar/SKILL.md +5 -3
  156. package/dist/plugin/skills/apt-watch-ci/SKILL.md +6 -4
  157. package/dist/schemas/feature-registry.d.ts.map +1 -1
  158. package/dist/schemas/feature-registry.js +34 -3
  159. package/dist/schemas/feature-registry.js.map +1 -1
  160. package/dist/types/config.d.ts +8 -5
  161. package/dist/types/config.d.ts.map +1 -1
  162. package/package.json +4 -4
  163. package/prompts/{conductor-framework-context.md → showrunner-framework-context.md} +1 -1
  164. package/prompts/{conductor-status-check.md → showrunner-status-check.md} +1 -1
  165. package/prompts/{conductor-sub-agent.md → showrunner-sub-agent.md} +6 -6
  166. package/prompts/{conductor-system.md → showrunner-system.md} +8 -8
  167. package/skills/apt/SKILL.md +112 -38
  168. package/skills/apt-close-task/SKILL.md +2 -2
  169. package/skills/apt-debug/SKILL.md +22 -24
  170. package/skills/apt-execute/SKILL.md +35 -26
  171. package/skills/apt-fan-out/SKILL.md +4 -4
  172. package/skills/apt-handoff/SKILL.md +1 -1
  173. package/skills/apt-mockup/SKILL.md +1 -1
  174. package/skills/apt-plan/SKILL.md +5 -5
  175. package/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
  176. package/skills/apt-produce/SKILL.md +606 -0
  177. package/skills/apt-quick/SKILL.md +27 -33
  178. package/skills/apt-review/SKILL.md +14 -11
  179. package/skills/apt-run/SKILL.md +132 -3
  180. package/skills/apt-ship/SKILL.md +29 -5
  181. package/skills/apt-spar/SKILL.md +5 -3
  182. package/skills/apt-watch-ci/SKILL.md +6 -4
  183. package/src/cli/artifacts/self-stage.mjs +2 -1
  184. package/src/cli/cli-wrappers/features-reconcile.mjs +9 -0
  185. package/src/cli/commands/ci-watch.mjs +51 -2
  186. package/src/cli/commands/commit.mjs +3 -3
  187. package/src/cli/commands/event.mjs +16 -16
  188. package/src/cli/commands/features-reconcile.mjs +157 -0
  189. package/src/cli/commands/health-check.mjs +2 -2
  190. package/src/cli/commands/merge-integrate.mjs +3 -3
  191. package/src/cli/commands/produce.mjs +1466 -0
  192. package/src/cli/commands/task.mjs +482 -285
  193. package/src/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
  194. package/src/cli/coordination/event-schema.d.ts +4 -2
  195. package/src/cli/coordination/event-schema.mjs +276 -21
  196. package/src/cli/coordination/store.mjs +4 -4
  197. package/src/cli/dispatch.mjs +4 -2
  198. package/src/cli/features/area-shape.mjs +140 -0
  199. package/src/cli/features/delta.mjs +625 -0
  200. package/src/cli/features/reconcile.mjs +1169 -0
  201. package/src/cli/features/surface-map.mjs +192 -0
  202. package/src/cli/features/write-root.mjs +140 -0
  203. package/src/cli/gate/gates/features-reconciled.mjs +70 -0
  204. package/src/cli/gate/gates/index.mjs +1 -0
  205. package/src/cli/help.mjs +31 -1
  206. package/src/cli/install/legacy-paths.mjs +2 -0
  207. package/src/cli/produce/blind-probe.mjs +245 -0
  208. package/src/cli/produce/claim.mjs +543 -0
  209. package/src/cli/produce/done-gate.mjs +238 -0
  210. package/src/cli/produce/events.mjs +131 -0
  211. package/src/cli/produce/evidence-oracle.mjs +133 -0
  212. package/src/cli/produce/ledger.mjs +284 -0
  213. package/src/cli/produce/probe-family.mjs +168 -0
  214. package/src/cli/produce/projection.mjs +105 -0
  215. package/src/cli/produce/run-id.mjs +84 -0
  216. package/src/cli/produce/saga.mjs +303 -0
  217. package/src/cli/produce/scheduler.mjs +423 -0
  218. package/src/cli/produce/setpoint.mjs +122 -0
  219. package/src/cli/produce/verification-ttl.mjs +191 -0
  220. package/src/cli/release-notes/ship-autodraft.mjs +2 -2
  221. package/src/cli/roadmap/showrunner-view.d.ts +10 -0
  222. package/src/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +6 -6
  223. package/src/cli/variant/gallery.mjs +7 -3
  224. package/templates/aperant-claude-md-appendix.md +2 -2
  225. package/workflows/scan-features.md +17 -11
  226. package/dist/cli/cli-wrappers/features-audit.d.mts +0 -2
  227. package/dist/cli/cli-wrappers/features-audit.d.mts.map +0 -1
  228. package/dist/cli/cli-wrappers/features-audit.mjs +0 -8
  229. package/dist/cli/cli-wrappers/features-audit.mjs.map +0 -1
  230. package/dist/cli/commands/features-audit.d.mts.map +0 -1
  231. package/dist/cli/commands/features-audit.mjs +0 -293
  232. package/dist/cli/commands/features-audit.mjs.map +0 -1
  233. package/dist/cli/features/registry-audit.d.mts +0 -56
  234. package/dist/cli/features/registry-audit.d.mts.map +0 -1
  235. package/dist/cli/features/registry-audit.mjs +0 -264
  236. package/dist/cli/features/registry-audit.mjs.map +0 -1
  237. package/dist/cli/roadmap/conductor-view.d.mts.map +0 -1
  238. package/dist/cli/roadmap/conductor-view.mjs.map +0 -1
  239. package/src/cli/cli-wrappers/features-audit.mjs +0 -8
  240. package/src/cli/commands/features-audit.mjs +0 -302
  241. package/src/cli/features/registry-audit.mjs +0 -254
  242. package/src/cli/roadmap/conductor-view.d.ts +0 -10
@@ -6,7 +6,7 @@ import { appendFileSync, mkdirSync, readdirSync, readFileSync, writeFileSync } f
6
6
  import { hostname } from 'node:os'
7
7
  import { join, resolve } from 'node:path'
8
8
  import { readLifecycleEventsForDay } from '../coordination/event-log.mjs'
9
- import { validateConductorEvent } from '../coordination/event-schema.mjs'
9
+ import { validateShowrunnerEvent } from '../coordination/event-schema.mjs'
10
10
  import { createCoordinationStore } from '../coordination/store.mjs'
11
11
  import { parseFlags } from '../util/args.mjs'
12
12
  import { err, ok } from '../util/result.mjs'
@@ -28,8 +28,8 @@ const VALID_EVENT_TYPES = [
28
28
  'ci-watch.tick',
29
29
  'ci-watch.fix-pushed',
30
30
  'ci-watch.stopped',
31
- // Phase 2.5 — Conductor-readable ops emitted by APT skills so the
32
- // Conductor's readEventLog tool can drive its observe loop. These
31
+ // Phase 2.5 — Showrunner-readable ops emitted by APT skills so the
32
+ // Showrunner's readEventLog tool can drive its observe loop. These
33
33
  // events route to JSONL (like ci-watch.*) and carry terminal_id
34
34
  // auto-stamped from APERANT_TERMINAL_ID when present.
35
35
  'phase.changed',
@@ -40,9 +40,9 @@ const VALID_EVENT_TYPES = [
40
40
  'budget.exceeded',
41
41
  'terminal.enrolled',
42
42
  'terminal.unenrolled',
43
- 'conductor.intent',
44
- 'conductor.cross_check',
45
- 'conductor.realignment',
43
+ 'showrunner.intent',
44
+ 'showrunner.cross_check',
45
+ 'showrunner.realignment',
46
46
  ]
47
47
 
48
48
  const CI_WATCH_EVENT_TYPES = new Set([
@@ -52,7 +52,7 @@ const CI_WATCH_EVENT_TYPES = new Set([
52
52
  'ci-watch.stopped',
53
53
  ])
54
54
 
55
- const CONDUCTOR_EVENT_TYPES = new Set([
55
+ const SHOWRUNNER_EVENT_TYPES = new Set([
56
56
  'phase.changed',
57
57
  'artifact.ready',
58
58
  'awaiting-input',
@@ -61,9 +61,9 @@ const CONDUCTOR_EVENT_TYPES = new Set([
61
61
  'budget.exceeded',
62
62
  'terminal.enrolled',
63
63
  'terminal.unenrolled',
64
- 'conductor.intent',
65
- 'conductor.cross_check',
66
- 'conductor.realignment',
64
+ 'showrunner.intent',
65
+ 'showrunner.cross_check',
66
+ 'showrunner.realignment',
67
67
  ])
68
68
 
69
69
  /**
@@ -142,22 +142,22 @@ export function cmdEvent(subcommand, projectDir, extraArgs) {
142
142
  return ok({ status: 'ok', command: 'event-append', event_file: jsonlFile, event })
143
143
  }
144
144
 
145
- // Phase 2.5 — Conductor-readable events route to the per-day JSONL
146
- // path with the canonical envelope the Conductor's readEventLog
145
+ // Phase 2.5 — Showrunner-readable events route to the per-day JSONL
146
+ // path with the canonical envelope the Showrunner's readEventLog
147
147
  // expects: { t, agent, pid, hostname, incarnation, op, task, data }.
148
148
  // terminal_id is auto-stamped from APERANT_TERMINAL_ID env when set,
149
- // so APT skills running in a Conductor-spawned PTY automatically
149
+ // so APT skills running in a Showrunner-spawned PTY automatically
150
150
  // tag their events with the originating terminal.
151
- if (CONDUCTOR_EVENT_TYPES.has(type)) {
151
+ if (SHOWRUNNER_EVENT_TYPES.has(type)) {
152
152
  const terminalId = process.env.APERANT_TERMINAL_ID
153
153
  if (terminalId && data && typeof data === 'object' && !data.terminal_id) {
154
154
  data.terminal_id = terminalId
155
155
  }
156
156
  // Step 1 — schema gate: reject payloads that violate the per-op
157
157
  // contract before the line lands on disk. The same validator
158
- // runs at the framework store seam and the core conductor
158
+ // runs at the framework store seam and the core showrunner
159
159
  // writer; gating here catches CLI emitters (APT skills).
160
- const validation = validateConductorEvent(type, data)
160
+ const validation = validateShowrunnerEvent(type, data)
161
161
  if (!validation.ok) {
162
162
  return err(`Schema violation for ${type}: ${validation.error}`)
163
163
  }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * commands/features-reconcile.mjs — CLI entry point for the feature-registry
3
+ * delta ledger (replaces the retired append-only registry-audit writer).
4
+ *
5
+ * Exactly ONE verb per invocation:
6
+ * --draft — scaffold/refresh a per-writer delta from `git diff
7
+ * --name-status <base>..HEAD` (renames preserved; deletions
8
+ * pre-filled `remove`; modifications marked needs-disposition).
9
+ * --write — the single ordered idempotent materializer (7 steps, ID-03):
10
+ * deltas → post-images → validate → atomic area replace →
11
+ * receipt → delete consumed deltas → regenerate REGISTRY.md.
12
+ * --check — read-only 4-clause verifier (ID-05): base..HEAD coverage with
13
+ * blob fingerprints, area schema validity, per-area latest-
14
+ * receipt integrity, no orphan consumed deltas.
15
+ * --gc — prune receipts present on origin/main AND older than
16
+ * --max-age-days (default 30). Fetch failure → warned no-op.
17
+ *
18
+ * Flags: --task-id, --subtask-id (draft), --base <ref> (draft/check; an
19
+ * explicit ref is normalized via `merge-base HEAD <ref>` — see resolveBase;
20
+ * default merge-base HEAD origin/main), --dry-run (draft), --warn-only
21
+ * (check), --max-age-days (gc), --no-worktree-redirect.
22
+ *
23
+ * BUG-025b: the mutating verbs (--draft/--write) resolve their write root via
24
+ * features/write-root.mjs so registry writes land in the active task's
25
+ * worktree, never leak onto main. --write self-stages its committable writes
26
+ * (self-stage.mjs contract) so the caller's next commit picks them up.
27
+ */
28
+
29
+ import { resolve } from 'node:path'
30
+ import { selfStageCommittableWrites } from '../artifacts/self-stage.mjs'
31
+ import { checkReconciled, draftDelta, gcReceipts, materialize } from '../features/reconcile.mjs'
32
+ import { resolveWriteRoot } from '../features/write-root.mjs'
33
+ import { parseFlags } from '../util/args.mjs'
34
+ import { err, exitWith, ok } from '../util/result.mjs'
35
+
36
+ const VERBS = ['draft', 'write', 'check', 'gc']
37
+
38
+ export function cmdFeaturesReconcile(projectDir, extraArgs) {
39
+ if (!projectDir) {
40
+ return err(
41
+ 'Usage: apt-tools features-reconcile <project-dir> (--draft|--write|--check|--gc) [flags]',
42
+ )
43
+ }
44
+ const root = resolve(projectDir)
45
+ const flags = parseFlags(extraArgs)
46
+ const verbs = VERBS.filter((v) => flags.has(v))
47
+ if (verbs.length !== 1) {
48
+ return err('features-reconcile requires exactly ONE of --draft | --write | --check | --gc', 1, {
49
+ command: 'features-reconcile',
50
+ })
51
+ }
52
+ const verb = verbs[0]
53
+
54
+ const taskIdFlag = flags.get('task-id')
55
+ const taskId = typeof taskIdFlag === 'string' && taskIdFlag.trim() ? taskIdFlag.trim() : null
56
+ const subtaskIdFlag = flags.get('subtask-id')
57
+ const subtaskId =
58
+ typeof subtaskIdFlag === 'string' && subtaskIdFlag.trim() ? subtaskIdFlag.trim() : null
59
+ const baseFlag = flags.get('base')
60
+ const base = typeof baseFlag === 'string' && baseFlag.trim() ? baseFlag.trim() : null
61
+ const noRedirect = flags.get('no-worktree-redirect') === true
62
+
63
+ // BUG-025b: only the MUTATING verbs redirect writes into the task worktree.
64
+ let writeRoot = root
65
+ let redirectNotice = null
66
+ if (verb === 'draft' || verb === 'write') {
67
+ const resolved = resolveWriteRoot({ projectDir: root, taskId, noRedirect })
68
+ if (resolved.error) {
69
+ return err(resolved.error.message, 1, {
70
+ command: 'features-reconcile',
71
+ kind: resolved.error.kind,
72
+ active_worktree_tasks: resolved.error.active_worktree_tasks,
73
+ })
74
+ }
75
+ writeRoot = resolved.writeRoot
76
+ redirectNotice = resolved.redirect_notice
77
+ if (redirectNotice) {
78
+ // Surface the redirect once on stderr so the executor's log carries
79
+ // the audit trail without polluting stdout JSON.
80
+ process.stderr.write(`[features-reconcile] ${redirectNotice}\n`)
81
+ }
82
+ }
83
+ const common = {
84
+ status: 'ok',
85
+ command: 'features-reconcile',
86
+ verb,
87
+ write_root: writeRoot,
88
+ ...(redirectNotice ? { redirect_notice: redirectNotice } : {}),
89
+ }
90
+
91
+ if (verb === 'draft') {
92
+ if (!taskId) {
93
+ return err(
94
+ 'features-reconcile --draft requires --task-id <id> (the delta path is per-writer)',
95
+ 1,
96
+ {
97
+ command: 'features-reconcile',
98
+ },
99
+ )
100
+ }
101
+ const res = draftDelta({
102
+ root: writeRoot,
103
+ base,
104
+ taskId,
105
+ subtaskId,
106
+ dryRun: flags.get('dry-run') === true,
107
+ })
108
+ if (!res.ok) return err(res.error, 1, { command: 'features-reconcile', verb })
109
+ return ok({
110
+ ...common,
111
+ delta_path: res.deltaPath,
112
+ wrote: res.wrote,
113
+ qualifying: res.qualifying,
114
+ base: res.base,
115
+ delta: res.delta,
116
+ })
117
+ }
118
+
119
+ if (verb === 'write') {
120
+ const res = materialize({ root: writeRoot, taskId })
121
+ if (res.status === 'error') {
122
+ return exitWith({ ...res, command: 'features-reconcile', verb, write_root: writeRoot }, 1)
123
+ }
124
+ let self_stage = null
125
+ if (res.status === 'ok' && Array.isArray(res.changed_paths) && res.changed_paths.length > 0) {
126
+ // Finally wiring the self-stage.mjs header contract: the write's
127
+ // committable outputs (areas + receipt + REGISTRY.md + deleted-delta
128
+ // paths) are staged so the ship-step commit picks them up.
129
+ self_stage = selfStageCommittableWrites(writeRoot, res.changed_paths)
130
+ }
131
+ return ok({
132
+ ...common,
133
+ ...res,
134
+ status: res.status,
135
+ ...(self_stage ? { self_stage } : {}),
136
+ })
137
+ }
138
+
139
+ if (verb === 'check') {
140
+ const res = checkReconciled({
141
+ root,
142
+ base,
143
+ warnOnly: flags.get('warn-only') === true,
144
+ taskId,
145
+ })
146
+ const envelope = { ...common, ...res, status: res.status }
147
+ if (res.status === 'fail') return exitWith(envelope, 1)
148
+ return ok(envelope)
149
+ }
150
+
151
+ // verb === 'gc'
152
+ const maxAgeFlag = flags.get('max-age-days')
153
+ const maxAgeDays =
154
+ typeof maxAgeFlag === 'string' && /^\d+$/.test(maxAgeFlag) ? Number(maxAgeFlag) : 30
155
+ const res = gcReceipts({ root, maxAgeDays })
156
+ return ok({ ...common, ...res, status: res.status, max_age_days: maxAgeDays })
157
+ }
@@ -16,8 +16,8 @@ const __dirname = dirname(__filename)
16
16
 
17
17
  /**
18
18
  * SECURITY: validate a component path string from `.aperant/features/*.json`
19
- * before passing it to git. The registry is on-disk JSON authored by
20
- * features-audit; pre-fix the orphan walker spliced this string into a
19
+ * before passing it to git. The registry is on-disk JSON written by the
20
+ * features-reconcile materializer; pre-fix the orphan walker spliced this string into a
21
21
  * shell command (`execSync(\`git rev-parse HEAD:${comp} 2>/dev/null\`)`),
22
22
  * making a malicious entry like `foo.ts; rm -rf $HOME` a command-injection
23
23
  * vector against any user who ran `apt-tools health-check`. The fix
@@ -8,7 +8,7 @@
8
8
  * exist, else stable by task id), and probes each branch's mergeability against
9
9
  * the CURRENT base via the EXACT same `git merge-tree` detection the `detect`
10
10
  * subcommand uses (#395). It emits a structured integration report the
11
- * conductor renders and the `apt:merge-conflict-resolution` flow consumes for
11
+ * showrunner renders and the `apt:merge-conflict-resolution` flow consumes for
12
12
  * any conflicted branch.
13
13
  *
14
14
  * READ-ONLY, like `detect`/`markers`: NO `git merge`, NO `git rebase`, NO index
@@ -33,7 +33,7 @@
33
33
  * apt-tools merge integrate <project-dir> --batch <batch-id> [--base <ref>]
34
34
  *
35
35
  * --tasks Explicit canonical task-id list (what `fan-out resolve` returns and
36
- * the conductor already holds). Primary form.
36
+ * the showrunner already holds). Primary form.
37
37
  * --batch Recover the task-id list from the batch's worker rows
38
38
  * `.aperant/team-status/fanout-<batch>-<task>.json` (the agent-id
39
39
  * format fan-out.mjs spawns workers with: `fanout-${batch}-${task}`).
@@ -291,7 +291,7 @@ export function mergeIntegrate(targetDir, extraArgs) {
291
291
  const task = state?.active_tasks?.[id] || null
292
292
 
293
293
  // Tasks with no shipped branch can't be integrated — record them so the
294
- // conductor sees why, but never block the rest of the batch.
294
+ // showrunner sees why, but never block the rest of the batch.
295
295
  if (!task) {
296
296
  needsHuman++
297
297
  tasks.push({ task_id: id, status: 'unknown', reason: 'task not found in state.json' })