create-agdf 0.30.0 → 0.32.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 (366) hide show
  1. package/generated/.agdf/control/README.md +5 -0
  2. package/generated/.agdf/control/templates/BRAND.md +28 -0
  3. package/generated/.agdf/control/templates/artefacts/PRD.md +11 -0
  4. package/generated/.agdf/control/templates/artefacts/SD.md +4 -0
  5. package/generated/.agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  6. package/generated/.opencode/agdf-interaction-locales.json +436 -2
  7. package/generated/.opencode/contracts/gate-artifact-preparation.md +9 -3
  8. package/generated/.opencode/contracts/interaction.md +10 -4
  9. package/generated/.opencode/contracts/modes.md +5 -0
  10. package/generated/.opencode/contracts/prd-definition.md +40 -1
  11. package/generated/.opencode/contracts/quality.md +35 -0
  12. package/generated/.opencode/contracts/request-activation.md +6 -3
  13. package/generated/.opencode/contracts/sd-definition.md +46 -0
  14. package/generated/.opencode/contracts/tp-definition.md +8 -0
  15. package/generated/.opencode/contracts/ur-definition.md +9 -5
  16. package/generated/.opencode/skills/agdf-ux-intent-definition/SKILL.md +31 -2
  17. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  18. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  19. package/generated/plugins/agdf/companion/events.mjs +119 -0
  20. package/generated/plugins/agdf/companion/figure.mjs +242 -111
  21. package/generated/plugins/agdf/companion/gate-bar.mjs +10 -28
  22. package/generated/plugins/agdf/companion/localization.mjs +15 -32
  23. package/generated/plugins/agdf/companion/notice.mjs +20 -10
  24. package/generated/plugins/agdf/companion/register.mjs +310 -66
  25. package/generated/plugins/agdf/companion/run-state.mjs +89 -90
  26. package/generated/plugins/agdf/companion/state.mjs +6 -32
  27. package/generated/plugins/agdf/companion/view.mjs +199 -24
  28. package/generated/plugins/agdf/control/README.md +5 -0
  29. package/generated/plugins/agdf/control/templates/BRAND.md +28 -0
  30. package/generated/plugins/agdf/control/templates/artefacts/PRD.md +11 -0
  31. package/generated/plugins/agdf/control/templates/artefacts/SD.md +4 -0
  32. package/generated/plugins/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  33. package/generated/plugins/agdf/mcp/server/README.md +26 -2
  34. package/generated/plugins/agdf/mcp/server/package.json +3 -3
  35. package/generated/plugins/agdf/mcp/server/src/generation-runtime.js +14 -3
  36. package/generated/plugins/agdf/mcp/server/src/generation.js +8 -2
  37. package/generated/plugins/agdf/mcp/server/src/main.js +5 -1
  38. package/generated/plugins/agdf/mcp/server/src/next-action.js +227 -0
  39. package/generated/plugins/agdf/mcp/server/src/prepared-call-transport.js +306 -0
  40. package/generated/plugins/agdf/mcp/server/src/safe-read-continuation.js +62 -0
  41. package/generated/plugins/agdf/mcp/server/src/server.js +155 -37
  42. package/generated/plugins/agdf/mcp/server/ui/cockpit.html +130 -33
  43. package/generated/plugins/agdf/mcp/server/ui/decision-manifest.json +3 -3
  44. package/generated/plugins/agdf/mcp/server/ui/decision.html +3 -3
  45. package/generated/plugins/agdf/mcp/server/ui/manifest.json +3 -3
  46. package/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  47. package/generated/plugins/agdf/meta/agdf-mcp-capability.json +1 -1
  48. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  49. package/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  50. package/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  51. package/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  52. package/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  53. package/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  54. package/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  55. package/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  56. package/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  57. package/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  58. package/generated/plugins/agdf/meta/copilot-payload-baseline.json +3 -3
  59. package/generated/plugins/agdf/meta/distribution-profile-history.json +14 -0
  60. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  61. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  62. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  63. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  64. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  65. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  66. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  67. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  68. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  69. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  70. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  71. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
  72. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
  73. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
  74. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
  75. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
  76. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
  77. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  78. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  79. package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +86 -83
  80. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
  81. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  82. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
  83. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
  84. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
  85. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
  86. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  87. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  88. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  89. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  90. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  91. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  92. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  93. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  94. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  95. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  96. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  97. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  98. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
  99. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
  100. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
  101. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit.js +47 -33
  102. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
  103. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  104. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
  105. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
  106. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
  107. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
  108. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
  109. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-read/cockpit-worker.js +1 -0
  110. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  111. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
  112. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
  113. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  114. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  115. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
  116. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
  117. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
  118. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
  119. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
  120. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  121. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
  122. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
  123. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  124. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
  125. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  126. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
  127. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
  128. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
  129. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
  130. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
  131. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
  132. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
  133. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
  134. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
  135. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  136. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  137. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
  138. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  139. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  140. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  141. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  142. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  143. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
  144. package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  145. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  146. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +4 -3
  147. package/generated/plugins/agdf/skills/ux-intent-definition/SKILL.md +31 -2
  148. package/generated/plugins/agdf/skills/ux-intent-definition/help.md +8 -1
  149. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  150. package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
  151. package/generated/plugins/agdf/submission/openai/release-notes.md +5 -8
  152. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
  153. package/generated/plugins/agdf-planning/.codex-plugin/plugin.json +1 -1
  154. package/generated/plugins/agdf-planning/plugin.json +1 -1
  155. package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +358 -203
  156. package/generated/plugins/copilot/agdf/control/README.md +5 -0
  157. package/generated/plugins/copilot/agdf/control/templates/BRAND.md +28 -0
  158. package/generated/plugins/copilot/agdf/control/templates/artefacts/PRD.md +11 -0
  159. package/generated/plugins/copilot/agdf/control/templates/artefacts/SD.md +4 -0
  160. package/generated/plugins/copilot/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
  161. package/generated/plugins/copilot/agdf/mcp/server/README.md +26 -2
  162. package/generated/plugins/copilot/agdf/mcp/server/package.json +3 -3
  163. package/generated/plugins/copilot/agdf/mcp/server/src/generation-runtime.js +14 -3
  164. package/generated/plugins/copilot/agdf/mcp/server/src/generation.js +8 -2
  165. package/generated/plugins/copilot/agdf/mcp/server/src/main.js +5 -1
  166. package/generated/plugins/copilot/agdf/mcp/server/src/next-action.js +227 -0
  167. package/generated/plugins/copilot/agdf/mcp/server/src/prepared-call-transport.js +306 -0
  168. package/generated/plugins/copilot/agdf/mcp/server/src/safe-read-continuation.js +62 -0
  169. package/generated/plugins/copilot/agdf/mcp/server/src/server.js +155 -37
  170. package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +1 -1
  171. package/generated/plugins/copilot/agdf/meta/distribution-profile-history.json +14 -0
  172. package/generated/plugins/copilot/agdf/plugin.json +1 -1
  173. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
  174. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  175. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  176. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
  177. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
  178. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
  179. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
  180. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
  181. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
  182. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
  183. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
  184. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
  185. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
  186. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
  187. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
  188. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
  189. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
  190. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  191. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  192. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +81 -78
  193. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
  194. package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +1 -1
  195. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
  196. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
  197. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
  198. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
  199. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  200. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  201. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  202. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  203. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  204. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  205. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  206. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  207. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  208. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  209. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  210. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  211. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
  212. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  213. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
  214. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
  215. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
  216. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
  217. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
  218. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  219. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
  220. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
  221. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  222. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  223. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
  224. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
  225. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
  226. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
  227. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
  228. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  229. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
  230. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
  231. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  232. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
  233. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  234. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
  235. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
  236. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
  237. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
  238. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
  239. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
  240. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
  241. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
  242. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
  243. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  244. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  245. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
  246. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  247. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  248. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  249. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  250. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  251. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
  252. package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  253. package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +2 -2
  254. package/generated/plugins/copilot/agdf/skills/agdf-interaction-locales.json +1 -1
  255. package/generated/plugins/copilot/agdf/skills/agdf-ux-intent-definition/SKILL.md +31 -2
  256. package/generated/plugins/copilot/agdf/skills/contracts/gate-artifact-preparation.md +9 -3
  257. package/generated/plugins/copilot/agdf/skills/contracts/interaction.md +10 -4
  258. package/generated/plugins/copilot/agdf/skills/contracts/modes.md +5 -0
  259. package/generated/plugins/copilot/agdf/skills/contracts/prd-definition.md +40 -1
  260. package/generated/plugins/copilot/agdf/skills/contracts/quality.md +35 -0
  261. package/generated/plugins/copilot/agdf/skills/contracts/request-activation.md +6 -3
  262. package/generated/plugins/copilot/agdf/skills/contracts/sd-definition.md +46 -0
  263. package/generated/plugins/copilot/agdf/skills/contracts/tp-definition.md +8 -0
  264. package/generated/plugins/copilot/agdf/skills/contracts/ur-definition.md +9 -5
  265. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
  266. package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +436 -2
  267. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
  268. package/generated/submissions/openai/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
  269. package/generated/submissions/openai/agdf/meta/contracts/interaction.md +10 -4
  270. package/generated/submissions/openai/agdf/meta/contracts/modes.md +5 -0
  271. package/generated/submissions/openai/agdf/meta/contracts/prd-definition.md +40 -1
  272. package/generated/submissions/openai/agdf/meta/contracts/quality.md +35 -0
  273. package/generated/submissions/openai/agdf/meta/contracts/request-activation.md +6 -3
  274. package/generated/submissions/openai/agdf/meta/contracts/sd-definition.md +46 -0
  275. package/generated/submissions/openai/agdf/meta/contracts/tp-definition.md +8 -0
  276. package/generated/submissions/openai/agdf/meta/contracts/ur-definition.md +9 -5
  277. package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +3 -3
  278. package/generated/submissions/openai/agdf/meta/distribution-profile-history.json +14 -0
  279. package/generated/submissions/openai/agdf/plugin.json +1 -1
  280. package/generated/submissions/openai/agdf/skills/ux-intent-definition/SKILL.md +31 -2
  281. package/generated/submissions/openai/agdf/skills/ux-intent-definition/help.md +8 -1
  282. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  283. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
  284. package/generated/submissions/openai/agdf/submission/openai/inventory.json +24 -24
  285. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  286. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  287. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  288. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +5 -8
  289. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
  290. package/lib/cli/command-registry.js +2 -1
  291. package/lib/cli/parse-args.js +7 -4
  292. package/lib/cli/project-read-command.js +29 -0
  293. package/lib/cli/validation-handlers.js +2 -1
  294. package/lib/mcp-dispatch-runtime.js +36 -7
  295. package/lib/mcp-lifecycle/package.js +7 -0
  296. package/lib/mcp-lifecycle/plugin-runtime.js +34 -6
  297. package/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
  298. package/lib/mcp-worker-runtime.js +86 -83
  299. package/lib/runtime/validator-application.js +2 -2
  300. package/lib/scaffold/plan.js +2 -0
  301. package/package.json +1 -1
  302. package/runtime/core/lib/companion/events.js +157 -0
  303. package/runtime/core/lib/companion/figure-state.js +38 -0
  304. package/runtime/core/lib/companion/journal.js +186 -0
  305. package/runtime/core/lib/companion/run-view.js +227 -0
  306. package/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
  307. package/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
  308. package/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
  309. package/runtime/core/lib/control-evaluation/gate-check.js +49 -7
  310. package/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
  311. package/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
  312. package/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
  313. package/runtime/core/lib/control-evaluation/report-decision.js +9 -0
  314. package/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
  315. package/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
  316. package/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
  317. package/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
  318. package/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
  319. package/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
  320. package/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
  321. package/runtime/core/lib/control-inspect/cockpit.js +47 -33
  322. package/runtime/core/lib/control-inspect/contract.js +64 -24
  323. package/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
  324. package/runtime/core/lib/control-inspect/project-state.js +2 -1
  325. package/runtime/core/lib/control-inspect/run-classification.js +31 -0
  326. package/runtime/core/lib/control-inspect/selection.js +6 -0
  327. package/runtime/core/lib/control-inspect/service.js +32 -5
  328. package/runtime/core/lib/control-inspect/work-situation.js +25 -0
  329. package/runtime/core/lib/control-read/cockpit-worker.js +1 -0
  330. package/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
  331. package/runtime/core/lib/control-state/input-resolution.js +7 -5
  332. package/runtime/core/lib/control-state/material-limits.js +4 -0
  333. package/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
  334. package/runtime/core/lib/control-state/presentation-delivery.js +4 -1
  335. package/runtime/core/lib/control-state/run-command-contract.js +10 -4
  336. package/runtime/core/lib/control-state/run-command-schema.js +9 -3
  337. package/runtime/core/lib/control-state/run-command-service.js +35 -11
  338. package/runtime/core/lib/control-state/run-create-command.js +6 -1
  339. package/runtime/core/lib/control-state/run-identity.js +2 -0
  340. package/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
  341. package/runtime/core/lib/control-state/run-inventory.js +12 -27
  342. package/runtime/core/lib/control-state/run-material.js +25 -7
  343. package/runtime/core/lib/control-state/run-presentation-render.js +113 -28
  344. package/runtime/core/lib/control-state/run-revision.js +38 -20
  345. package/runtime/core/lib/control-state/run-source-revisions.js +37 -17
  346. package/runtime/core/lib/control-state/run-state-reader.js +10 -3
  347. package/runtime/core/lib/control-state/run-steps.js +8 -5
  348. package/runtime/core/lib/control-state/run-title.js +43 -0
  349. package/runtime/core/lib/index.js +3 -1
  350. package/runtime/core/lib/interaction-catalog-validation.js +7 -1
  351. package/runtime/core/lib/interaction-catalog.js +8 -0
  352. package/runtime/core/lib/interaction-presentation.js +31 -10
  353. package/runtime/core/lib/mcp-input-hints.js +30 -1
  354. package/runtime/core/lib/mcp-tool-errors.js +5 -3
  355. package/runtime/core/lib/resources/canonical-init-plan.js +1 -1
  356. package/runtime/core/lib/runtime/plugin-provenance.js +9 -2
  357. package/runtime/core/lib/skill-dispatch/contract.js +6 -4
  358. package/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
  359. package/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
  360. package/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
  361. package/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
  362. package/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
  363. package/runtime/core/lib/skill-dispatch/service.js +17 -4
  364. package/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
  365. package/generated/plugins/agdf/companion/core.mjs +0 -16
  366. package/generated/plugins/agdf/companion/locales.json +0 -200
@@ -1,13 +1,18 @@
1
- // AGDF Companion host adapter (SDD-07 to SDD-10; follow-up SDD-05 to SDD-12): the `/agdf-companion`
2
- // command, the persisted choices, main-loop turn observation, the refresh cadence, the own pane, the
3
- // status line and toasts. Observation only: no gating hook, every hook passes its event on through a
4
- // catch path, and nothing is written under .agdf/control. Session state lives in this module and is
1
+ // AGDF Companion host adapter (SDD-07 to SDD-10; follow-up SDD-05 to SDD-12; companion core SDD-007, SDD-010):
2
+ // the `/agdf-companion` command, the persisted choices, main-loop turn observation, the refresh cadence,
3
+ // the own pane, the status line and toasts. Run state comes only from the plugin runtime's read-only
4
+ // `run-view` command through `$.process`, called on a changed run-file fingerprint, a new journal event
5
+ // of this root or a changed language; the companion imports no Core module. Observation only: no
6
+ // gating hook, every hook passes its event on through a catch path, and nothing is written under
7
+ // .agdf/control. Session state lives in this module and is
5
8
  // redrawn through `$.ui.invalidate`. Elements come from the surface table and are built with the
6
9
  // host's global `h`.
7
10
 
8
11
  import { assignRun, namedRun, openRuns, stepSelection } from './assignment.mjs';
9
- import { figureSvg } from './figure.mjs';
10
- import { chatLocale, label } from './localization.mjs';
12
+ import { EVENT_POLL_MS, JOURNAL_FILE, JOURNAL_READ_LIMIT, JOURNAL_ROTATED_FILE, PANE_EVENTS, STICKY_KINDS, TOAST_KINDS, eventText,
13
+ isConfirmed, isStillUncertain, journalDirectory, namedEventText, parseJournal, unseenEvents } from './events.mjs';
14
+ import { figureSvg, observeFigure } from './figure.mjs';
15
+ import { chatLocale, companionLabels, gateTitle, label } from './localization.mjs';
11
16
  import { CHIME, chimeClip, noticeText, observeNotice, observedRun, statusText } from './notice.mjs';
12
17
  import { STATE_FILE, defaultCompanionState, parseCompanionState, pluginDataDir, serializeCompanionState } from './persistence.mjs';
13
18
  import { readSnapshot, settleSnapshot } from './run-state.mjs';
@@ -34,12 +39,21 @@ const BODY_RESERVE = 0;
34
39
  // stay beside the widest bar (owner request of 2026-10-28); a narrower pane lists the ids alone.
35
40
  const ID_ROOM = 18;
36
41
  const COLOR = Object.freeze({ laeuft: 'suggestion', baut: 'suggestion', wartet: 'warning', blockiert: 'error', fertig: 'success' });
42
+ // The colour of the "whose move" line: yours, the agent's, or a block.
43
+ const TURN_COLOR = Object.freeze({ you: 'warning', claude: 'suggestion', halt: 'error', next: undefined });
37
44
 
38
45
  function createSession() {
39
- return { startedAt: 0, root: '', registry: null, labels: null, locale: 'en', statePath: null, version: null, icon: null,
40
- choices: defaultCompanionState(), isHidden: false, snapshot: null, isTurnActive: false, isObjectiveExpanded: false,
41
- isAboutShown: false, isMenuOpen: false, timer: null, reads: 0, appliedRead: 0, observation: null,
42
- chatMention: null, isBrowsing: false, conversation: null };
46
+ return { startedAt: 0, root: '', registry: null, labels: null, locale: 'en', statePath: null, dataDir: null, version: null, icon: null,
47
+ choices: defaultCompanionState(), isHidden: false, snapshot: null, isTurnActive: false, isInfoExpanded: false,
48
+ isPreviewExpanded: false, isAboutShown: false, isMenuOpen: false, timer: null, eventTimer: null, reads: 0, appliedRead: 0,
49
+ observation: null, figureObservation: null, chatMention: null, isBrowsing: false, conversation: null,
50
+ // Companion core SDD-007: the run-file fingerprint of the last run-view call, the journal cursor and
51
+ // stamp, this root's events since the last main-loop turn and the drift warnings already announced.
52
+ fingerprint: null, journalCursor: null, journalStamp: null, eventsAvailable: null, events: [], driftSeen: null,
53
+ // Durable events of this root waiting for a fresh run view to confirm them (CR delta review RV-1).
54
+ unconfirmed: [],
55
+ // The start's first read, running beside the host (CR finding B5).
56
+ background: null };
43
57
  }
44
58
 
45
59
  // One companion per session: the module is loaded once per session.
@@ -47,8 +61,15 @@ const session = createSession();
47
61
  const t = (path, params) => label(session.labels, session.locale, path, params);
48
62
  const selection = () => session.choices.selections[session.root] ?? null;
49
63
  const redraw = $ => $.ui.invalidate('ui.render');
50
- // File access for the host-independent reader, each call spelled on `$` (read-only).
51
- const files = $ => ({ exists: path => $.fs.exists(path), list: path => $.fs.list(path), read: path => $.fs.read(path) });
64
+ // Event toasts name a run only when it is not the run the status line and toasts follow; another run
65
+ // is named by its objective (owner request of 2026-11-06, T-013).
66
+ const eventNaming = () => ({
67
+ shownRunId: observedRun({ snapshot: session.snapshot, sessionStartedAt: session.startedAt, selection: selection(), mention: session.chatMention }).runId ?? null,
68
+ runs: session.snapshot?.status === 'ok' ? session.snapshot.runs : [] });
69
+ // The host loads a hooks module only when every use of `$` is spelled `$.noun.member(...)` at the call
70
+ // site; passing `$.process` itself refuses the whole module (T-013 native check). The run-view reader
71
+ // receives this call-site wrapper instead.
72
+ const processes = $ => ({ run: (argv, init) => $.process.run(argv, init) });
52
73
 
53
74
  // Applies one change to this session's choices and, where the AGDF plugin data directory already
54
75
  // exists, to the freshly read state file, so choices another session stored meanwhile survive.
@@ -67,7 +88,7 @@ async function persist($, change) {
67
88
  // The status line and toasts follow the run-derived state of the run the panel shows without browsing,
68
89
  // so browsing never changes them (follow-up SDD-05 to SDD-07; chat-run navigation SDD-06). A stale snapshot keeps the last observation, so a failed read never
69
90
  // announces anything. Each host call has its own catch path: a missing channel stays silent (SDD-12).
70
- function announce($) {
91
+ function announce($, { quiet = new Set() } = {}) {
71
92
  const observed = observedRun({ snapshot: session.snapshot, sessionStartedAt: session.startedAt, selection: selection(),
72
93
  mention: session.chatMention });
73
94
  // Every applied read sets the line again, unchanged text included: the desktop dropped the one set
@@ -76,16 +97,33 @@ function announce($) {
76
97
  if (session.snapshot?.stale) return;
77
98
  const { observation, notice } = observeNotice(session.observation, observed);
78
99
  session.observation = observation;
79
- if (!notice || !session.choices.notice) return;
80
- try {
81
- $.ui.toast(noticeText(observed.runId, notice, { registry: session.registry, labels: session.labels, locale: session.locale }));
82
- } catch {
83
- return; // no toast on this host, and so no chime either (CR-F01)
84
- }
100
+ // A run whose own event raises a toast in the same read gets no second state toast (decision P1).
101
+ if (notice && !quiet.has(observed.runId)) toast($, noticeText(notice, { registry: session.registry, labels: session.labels, locale: session.locale }));
102
+ announceDrift($);
103
+ }
104
+
105
+ // One toast, with the chime only when it was shown; a missing channel stays silent (SDD-12, CR-F01).
106
+ function toast($, text) {
107
+ if (!session.choices.notice) return false;
108
+ try { $.ui.toast(text); } catch { return false; }
85
109
  // The chime plays only with a shown toast; a host without a player skips it, a failure stays silent.
86
110
  if (session.choices.sound) {
87
111
  try { $.audio.play(chimeClip(), { gain: CHIME.gain }).catch(() => {}); } catch { /* no audio on this host */ }
88
112
  }
113
+ return true;
114
+ }
115
+
116
+ // A bound document changed after recording raises one toast per change (decision P1, PRD AC-008); the
117
+ // pane keeps the warning while the run view reports it. The first read is a baseline.
118
+ function announceDrift($) {
119
+ if (session.snapshot?.status !== 'ok') return;
120
+ const warnings = session.snapshot.runs.flatMap(run => (run.drift ?? []).map(item => ({ run: run.id, document: item.document,
121
+ key: `${run.id}|${item.path}|${item.current_digest}` })));
122
+ const seen = session.driftSeen;
123
+ session.driftSeen = new Set(warnings.map(item => item.key));
124
+ if (!seen) return;
125
+ const naming = eventNaming();
126
+ for (const item of warnings.filter(warning => !seen.has(warning.key))) toast($, namedEventText(t('events.drift', { document: item.document }), item.run, t, naming));
89
127
  }
90
128
 
91
129
  // Switching off clears the status line, forgets the observation and discards reads still running, so
@@ -96,19 +134,46 @@ function silence($) {
96
134
  try { $.ui.status(undefined); } catch { /* no status line on this host */ }
97
135
  }
98
136
 
99
- // Reads the run states of the current project root, which `/cd` or a worktree move can change.
137
+ // Reads the run view of the current project root, which `/cd` or a worktree move can change; a
138
+ // remembered selection is requested by id, so a selected completed run is shown in full.
100
139
  // Only the newest of overlapping reads is applied. A snapshot without any runs, as during a branch
101
140
  // switch, never drops the remembered selection.
102
- async function refresh($) {
141
+ async function refresh($, { quiet } = {}) {
103
142
  const read = ++session.reads;
104
143
  try {
105
144
  const root = await $.session.root();
106
145
  await followConversation($);
107
- const next = await readSnapshot(files($), root, { now: await $.clock.now() });
146
+ const remembered = session.choices.selections[root];
147
+ // Keep evaluating the run already followed in this project when it leaves the active list;
148
+ // its completed state must be confirmed before the companion celebrates.
149
+ const observed = root === session.root ? observedRun({ snapshot: session.snapshot, sessionStartedAt: session.startedAt,
150
+ selection: remembered, mention: session.chatMention }).runId : null;
151
+ const runIds = [...new Set([remembered, observed].filter(Boolean))];
152
+ // Taken before the call: a change during the call shows up at the next check.
153
+ const ids = fingerprintIds(root);
154
+ const print = await fingerprint($, root, ids);
155
+ const next = await readSnapshot(processes($), { pluginRoot: $.plugin.root, root, language: session.locale,
156
+ runIds, now: await $.clock.now(), clock: () => $.clock.now() });
108
157
  if (read < session.appliedRead) return;
109
158
  session.appliedRead = read;
159
+ if (root !== session.root) {
160
+ // Another project root: its drift baseline, pane entries and preview start over (CR finding B3).
161
+ session.driftSeen = null;
162
+ session.snapshot = null;
163
+ session.figureObservation = null;
164
+ session.events = [];
165
+ session.unconfirmed = [];
166
+ session.isPreviewExpanded = false;
167
+ }
110
168
  session.root = root;
111
169
  session.snapshot = settleSnapshot(session.snapshot, next);
170
+ if (next.status === 'ok') session.events = session.events.filter(event => !STICKY_KINDS.includes(event.kind) || isStillUncertain(event, next.runs));
171
+ // A changed set of open runs is listed again, so the next check compares like with like. A failed
172
+ // read keeps no fingerprint, so the next check reads again (CR finding B1); so does a view with a
173
+ // run that ran into the read budget, which may read on the next attempt.
174
+ const after = fingerprintIds(root);
175
+ session.fingerprint = next.status === 'failed' || next.retry ? null
176
+ : `${session.locale}|${after.join() === ids.join() ? print : await fingerprint($, root, after)}`;
112
177
  const chosen = selection();
113
178
  if (chosen && next.status === 'ok' && next.runs.length) {
114
179
  const { dropSelection } = assignRun({ runs: next.runs, sessionStartedAt: session.startedAt, selection: chosen });
@@ -117,12 +182,105 @@ async function refresh($) {
117
182
  } catch (error) {
118
183
  if (read < session.appliedRead) return;
119
184
  session.appliedRead = read;
120
- session.snapshot = settleSnapshot(session.snapshot, { status: 'failed', runs: [], unreadable: [], readAt: Date.now(), error: String(error?.message ?? error) });
185
+ session.fingerprint = null;
186
+ session.snapshot = settleSnapshot(session.snapshot, { status: 'failed', runs: [], unreadable: [], readAt: Date.now(), error: 'unavailable' });
121
187
  }
122
- if (session.choices.enabled) announce($);
188
+ if (session.choices.enabled) announce($, { quiet });
123
189
  redraw($);
124
190
  }
125
191
 
192
+ // The run-file fingerprint (SDD-007): the run folders, `config.json` and, for each open or selected
193
+ // run, its RUN_STATE, documents and evidence entries with size and modification time from `$.fs.list`:
194
+ // the files the run view compares for drift (bound documents and evidence reports). It reads listings
195
+ // only, never a run file.
196
+ const fingerprintIds = root => [...new Set([...(session.snapshot?.runs ?? []).filter(run => run.lifecycle === 'active').map(run => run.id),
197
+ session.choices.selections[root]].filter(Boolean))].sort();
198
+
199
+ async function fingerprint($, root, ids = fingerprintIds(root)) {
200
+ const list = async path => { try { return await $.fs.list(path); } catch { return null; } };
201
+ const files = entries => (entries ?? []).filter(entry => entry.kind === 'file').map(entry => `${entry.name}:${entry.size}:${entry.mtimeMs}`).sort().join(',');
202
+ const control = `${root}/.agdf/control`;
203
+ const runs = await list(`${control}/runs`);
204
+ const parts = [`config:${files((await list(control))?.filter(entry => entry.name === 'config.json'))}`,
205
+ `runs:${(runs ?? []).map(entry => entry.name).sort().join(',')}`];
206
+ for (const id of ids) {
207
+ const folders = [];
208
+ for (const folder of ['', '/documents', '/evidence']) folders.push(files(await list(`${control}/runs/${id}${folder}`)));
209
+ parts.push(`${id}:${folders.join('|')}`);
210
+ }
211
+ return parts.join(';');
212
+ }
213
+
214
+ // The 30-second check and the check after a main-loop turn (SDD-007): the run view is read again only
215
+ // when the conversation, the root, the language or the run-file fingerprint changed.
216
+ async function check($) {
217
+ try {
218
+ const root = await $.session.root();
219
+ session.locale = await readLocale($, root);
220
+ const conversationChanged = await followConversation($);
221
+ if (!conversationChanged && root === session.root && `${session.locale}|${await fingerprint($, root)}` === session.fingerprint) return false;
222
+ await refresh($);
223
+ return true;
224
+ } catch {
225
+ return false;
226
+ }
227
+ }
228
+
229
+ // Reads the journal (SDD-007): a bounded read of its own file in the plugin data directory, only when
230
+ // its size or time changed. New events of this root are kept for the pane, read the run view once and
231
+ // raise the toasts of decision P1. A missing or unreadable journal shows "events unavailable".
232
+ async function pollEvents($) {
233
+ const available = value => { if (session.eventsAvailable !== value) { session.eventsAvailable = value; redraw($); } };
234
+ try {
235
+ if (!session.dataDir) { available(false); return; }
236
+ // The current root, which `/cd` or a worktree move can change since the last read (CR finding B3).
237
+ const root = await $.session.root();
238
+ if (root !== session.root) await refresh($);
239
+ const directory = journalDirectory(session.dataDir);
240
+ const listing = await $.fs.list(directory);
241
+ const entry = listing.find(item => item.name === JOURNAL_FILE && item.kind === 'file');
242
+ if (!entry || entry.size > JOURNAL_READ_LIMIT) { available(false); return; }
243
+ const stamp = `${entry.size}:${entry.mtimeMs}`;
244
+ let fresh = [];
245
+ if (stamp !== session.journalStamp) {
246
+ let events = parseJournal(await $.fs.read(`${directory}/${JOURNAL_FILE}`));
247
+ // Lines written after the last read but before a rotation sit in the rotation file (CR finding B6).
248
+ const cursorId = session.journalCursor?.id;
249
+ const rotated = listing.find(item => item.name === JOURNAL_ROTATED_FILE && item.kind === 'file');
250
+ if (cursorId && !events.some(event => event.id === cursorId) && rotated && rotated.size <= JOURNAL_READ_LIMIT) {
251
+ events = parseJournal(await $.fs.read(`${directory}/${JOURNAL_ROTATED_FILE}`)).concat(events);
252
+ }
253
+ session.journalStamp = stamp;
254
+ const unseen = unseenEvents(events, { root, cursor: session.journalCursor });
255
+ fresh = unseen.fresh;
256
+ session.journalCursor = unseen.cursor;
257
+ }
258
+ available(true);
259
+ if (!fresh.length && !session.unconfirmed.length) return;
260
+ if (fresh.length) {
261
+ const toasts = fresh.filter(event => TOAST_KINDS.includes(event.kind));
262
+ await refresh($, { quiet: new Set(toasts.map(event => event.run_id)) });
263
+ }
264
+ // A durable fact is shown, in the pane and as a toast, only once the run view confirms it (SD 2,
265
+ // CR finding B4). Without a fresh view it waits for one instead of being dropped (CR delta review
266
+ // RV-1); a fresh view that does not confirm it drops it.
267
+ const current = session.snapshot?.status === 'ok' && !session.snapshot.stale;
268
+ const runs = current ? session.snapshot.runs : [];
269
+ const candidates = session.unconfirmed.concat(fresh);
270
+ const shown = candidates.filter(event => isConfirmed(event, runs));
271
+ session.unconfirmed = current ? [] : candidates.filter(event => !shown.includes(event)).slice(-PANE_EVENTS);
272
+ if (!shown.length) return;
273
+ session.events = [...shown].reverse().concat(session.events).slice(0, PANE_EVENTS);
274
+ if (!session.choices.enabled) { redraw($); return; }
275
+ const gate = value => gateTitle(session.registry, session.locale, value);
276
+ const naming = eventNaming();
277
+ for (const event of shown.filter(item => TOAST_KINDS.includes(item.kind))) toast($, eventText(event, t, { gateTitle: gate, ...naming }));
278
+ redraw($);
279
+ } catch {
280
+ available(false);
281
+ }
282
+ }
283
+
126
284
  // Takes the last open run a main-loop text names as the chat's run at host time `at` (chat-run navigation
127
285
  // SDD-01, SDD-02). Returns whether a mention was recorded: a repeated name can still move the chat's run
128
286
  // back from a later change, so every recorded mention is announced (CR-F02).
@@ -139,43 +297,50 @@ function noteMention(text, at) {
139
297
  async function followConversation($) {
140
298
  let conversation = session.conversation;
141
299
  try { conversation = await $.session.id(); } catch { /* no conversation id on this host */ }
142
- if (session.conversation && conversation !== session.conversation) {
300
+ const changed = Boolean(session.conversation) && conversation !== session.conversation;
301
+ if (changed) {
143
302
  session.chatMention = null;
144
303
  session.isBrowsing = false;
145
304
  session.observation = null;
146
305
  session.startedAt = await $.clock.now();
147
306
  }
148
307
  session.conversation = conversation;
308
+ return changed;
149
309
  }
150
310
 
151
311
  function stopRefreshing() {
152
312
  session.timer?.cancel();
313
+ session.eventTimer?.cancel();
153
314
  session.timer = null;
315
+ session.eventTimer = null;
154
316
  }
155
317
 
156
- // The timer is replaced before the first read, so overlapping starts never leave a second timer.
318
+ // The timers are replaced before the first read, so overlapping starts never leave a second one: the
319
+ // journal is read every 2 seconds, the run files are checked every 30 seconds (SDD-007). Events written
320
+ // before the start are history, never announced.
157
321
  async function startRefreshing($) {
158
322
  stopRefreshing();
159
- session.timer = $.clock.every(REFRESH_MS, () => { void refresh($); });
160
- await refresh($);
323
+ session.journalCursor = { id: null, at: new Date(await $.clock.now()).toISOString() };
324
+ session.journalStamp = null;
325
+ session.eventTimer = $.clock.every(EVENT_POLL_MS, () => { void pollEvents($); });
326
+ session.timer = $.clock.every(REFRESH_MS, () => { void check($); });
327
+ // The first read runs beside the host: session start and the command never wait for the run-view
328
+ // process (CR finding B5); the pane draws "reading" until it lands.
329
+ session.background = (async () => { await refresh($); await pollEvents($); })().catch(() => {});
161
330
  return $.ui.open({ id: PANE, title: t('title') });
162
331
  }
163
332
 
333
+ // Settles once the latest background read finished (for the adapter test).
334
+ export const whenIdle = () => session.background ?? Promise.resolve();
335
+
164
336
  const openedText = opened => (opened?.isPlaced === false ? t('command.waiting', { reason: opened.reason }) : t('command.enabled'));
165
337
 
166
338
  async function loadSession($) {
167
339
  session.startedAt = await $.clock.now();
168
340
  session.root = await $.session.root();
169
- session.labels = JSON.parse(await $.fs.read(`${$.plugin.root}/companion/locales.json`));
170
341
  session.registry = JSON.parse(await $.fs.read(`${$.plugin.root}/meta/agdf-interaction-locales.json`));
171
- const config = `${session.root}/.agdf/control/config.json`;
172
- const configText = (await $.fs.exists(config)) ? await $.fs.read(config) : null;
173
- // Without AGDF control, Claude's own `language` setting chooses the language (follow-up SDD-11).
174
- let setting = null;
175
- if (configText === null) {
176
- try { setting = await $.settings.read({ key: 'language' }); } catch { /* no setting: the fallback locale */ }
177
- }
178
- session.locale = chatLocale(session.registry, configText, { setting, labels: session.labels });
342
+ session.labels = companionLabels(session.registry);
343
+ session.locale = await readLocale($, session.root);
179
344
  // The About entry names the plugin version; a missing or unreadable manifest only leaves it out.
180
345
  try {
181
346
  const { version } = JSON.parse(await $.fs.read(`${$.plugin.root}/.claude-plugin/plugin.json`));
@@ -188,15 +353,31 @@ async function loadSession($) {
188
353
  } catch { /* no icon shown */ }
189
354
  const dir = pluginDataDir({ configDir: await $.env.get('CLAUDE_CONFIG_DIR'), userProfile: await $.env.get('USERPROFILE'), home: await $.env.get('HOME') });
190
355
  session.statePath = dir ? `${dir}/${STATE_FILE}` : null;
356
+ // The MCP server journals below the same plugin data root (companion core SDD-006).
357
+ session.dataDir = dir;
191
358
  if (session.statePath && (await $.fs.exists(session.statePath))) session.choices = parseCompanionState(await $.fs.read(session.statePath));
192
359
  }
193
360
 
361
+ // The AGDF chat language of the project; without AGDF control, Claude's own `language` setting
362
+ // (follow-up SDD-11). Read again at every check, so a language change reads the run view again.
363
+ async function readLocale($, root) {
364
+ const config = `${root}/.agdf/control/config.json`;
365
+ const configText = (await $.fs.exists(config)) ? await $.fs.read(config) : null;
366
+ let setting = null;
367
+ if (configText === null) {
368
+ try { setting = await $.settings.read({ key: 'language' }); } catch { /* no setting: the fallback locale */ }
369
+ }
370
+ return chatLocale(session.registry, configText, { setting, labels: session.labels });
371
+ }
372
+
194
373
  const wrappedRows = (value, columns) => (value ? Math.ceil(value.length / Math.max(columns, 10)) : 0);
195
374
 
196
375
  // How many open runs the desktop list shows: the body rows left beside the other blocks, never fewer
197
376
  // than the terminal's six (the pane then scrolls). One row of them goes to "+ N more" when runs remain.
198
377
  export function listCapacity(view, { rows, columns, isAboutShown = false }) {
199
- const blocks = [view.message, view.hint, view.stale].filter(Boolean);
378
+ const blocks = [view.message, view.hint, view.unreadableHint !== view.message ? view.unreadableHint : null, view.stale,
379
+ ...(view.drift ?? []), ...(view.events ? [view.events.join(' '), ...view.events.map(() => ' ')] : []),
380
+ ...(view.review ? [view.review.summary, view.review.match, ' ', ' '] : []), view.eventsHint].filter(Boolean);
200
381
  const fixed = DESKTOP_ROWS.figure + DESKTOP_ROWS.footer + DESKTOP_ROWS.spare + (isAboutShown ? DESKTOP_ROWS.about : 0) + 1
201
382
  + blocks.reduce((sum, value) => sum + wrappedRows(value, columns), 0) + DESKTOP_ROWS.gap * (blocks.length + 3);
202
383
  return Math.max(LISTED_RUNS, Math.floor(rows - fixed));
@@ -209,14 +390,24 @@ export function fitRunId(id, room) {
209
390
  return `${id.slice(0, room - 1 - tail)}…${id.slice(id.length - tail)}`;
210
391
  }
211
392
 
393
+ // A run name cut at its end to `room` characters; a name reads from its start, unlike an id.
394
+ export function fitRunName(name, room) {
395
+ return name.length <= room ? name : `${name.slice(0, Math.max(1, room - 1))}…`;
396
+ }
397
+
212
398
  const press = ($, action) => async () => {
213
399
  try { await action(); } catch { /* a failed action leaves the last drawing */ }
214
400
  redraw($);
215
401
  };
216
402
 
217
- function body($, e, view) {
403
+ function body($, e) {
218
404
  const { Box, Text, Button, Svg, Link, Select } = $.ui.resolve(e);
219
405
  const isTerminal = e.surface === 'terminal' || !Svg;
406
+ const view = buildPanelView({ snapshot: session.snapshot, sessionStartedAt: session.startedAt, selection: selection(),
407
+ mention: session.chatMention, isBrowsing: session.isBrowsing, showRunState: !isTerminal,
408
+ isTurnActive: session.isTurnActive, registry: session.registry, labels: session.labels, locale: session.locale,
409
+ columns: e.props?.bodyColumns ?? Infinity, isInfoExpanded: session.isInfoExpanded,
410
+ events: session.events, eventsAvailable: session.eventsAvailable ?? undefined });
220
411
  const rows = e.props?.scroll?.bodyRows;
221
412
  const fits = Number.isInteger(rows) && rows > 0;
222
413
  const columns = Number.isInteger(e.props?.bodyColumns) ? e.props.bodyColumns : 40;
@@ -238,7 +429,7 @@ function body($, e, view) {
238
429
  const commands = [
239
430
  ...(canReturn ? [['chat', t('actions.backToChat'), back]] : []),
240
431
  ['still', session.choices.still ? t('actions.stillOff') : t('actions.stillOn'), toggle('still')],
241
- ['retry', t('actions.retry'), () => refresh($)],
432
+ ['retry', t('actions.retry'), async () => { session.journalStamp = null; await refresh($); await pollEvents($); }],
242
433
  ['notice', session.choices.notice ? t('actions.noticeOff') : t('actions.noticeOn'), toggle('notice')],
243
434
  ['sound', session.choices.sound ? t('actions.soundOff') : t('actions.soundOn'), toggle('sound')],
244
435
  ['about', t('actions.about'), async () => { session.isAboutShown = true; }],
@@ -277,14 +468,15 @@ function body($, e, view) {
277
468
  // The terminal keeps its six; the desktop lists as many as fit and gives the last row to "+ N more".
278
469
  const listed = isTerminal ? view.openRuns.slice(0, LISTED_RUNS)
279
470
  : view.openRuns.length <= capacity ? view.openRuns : view.openRuns.slice(0, capacity - 1);
280
- // One listed run: the id as a plain button and, where the pane has room for the widest listed bar, its
281
- // condensed gate bar at the right edge, every id shortened to the same room (the same rule for all rows,
282
- // live check of 2026-10-28). The bar keeps its width; an id that still runs over is cut by the surface.
471
+ // One listed run: its name as a plain button (owner request of 2026-11-11: a run id tells a person
472
+ // nothing) and, where the pane has room for the widest listed bar, its condensed gate bar at the right
473
+ // edge, every name cut to the same room (the same rule for all rows, live check of 2026-10-28). The bar
474
+ // keeps its width; a name that still runs over is cut by the surface.
283
475
  const widest = Math.max(0, ...listed.map(run => run.bar?.length ?? 0));
284
476
  const room = columns - widest - 2;
285
477
  const withBars = widest > 0 && room >= ID_ROOM;
286
478
  const runRow = run => {
287
- const id = h(Button, { key: `run-${run.id}`, plain: true, label: withBars ? fitRunId(run.id, room) : run.id, onPress: select(run.id) });
479
+ const id = h(Button, { key: `run-${run.id}`, plain: true, label: fitRunName(run.name ?? run.id, withBars ? room : columns), onPress: select(run.id) });
288
480
  return withBars && run.bar
289
481
  ? h(Box, { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 1 },
290
482
  h(Box, { flexShrink: 1 }, id), h(Box, { flexShrink: 0 }, h(Text, { dimColor: true, mono: true }, run.bar)))
@@ -306,34 +498,82 @@ function body($, e, view) {
306
498
  ...listed.map(runRow),
307
499
  !isTerminal && view.openRuns.length > listed.length ? h(Text, { dimColor: true }, t('fields.moreRuns', { count: view.openRuns.length - listed.length })) : null))
308
500
  : null;
501
+ // The (i) opens the run's details on purpose (owner request of 2026-11-12); closed by default and
502
+ // only offered when there is something behind it. The label names the action, so it reads alone.
503
+ const infoButton = view.info?.length ? h(Button, { key: 'info', plain: true,
504
+ label: view.isInfoExpanded ? t('actions.infoHide') : t('actions.infoShow'),
505
+ onPress: press($, async () => { session.isInfoExpanded = !session.isInfoExpanded; }) }) : null;
309
506
  if (isTerminal) {
310
507
  return h(Box, { flexDirection: 'column', gap: 1 },
311
- h(Text, { color: COLOR[view.mood] }, terminalText(view, { labels: session.labels, locale: session.locale })), runList, about, actions);
508
+ h(Text, { color: view.resting ? undefined : COLOR[view.mood] }, terminalText(view, { labels: session.labels, locale: session.locale })), infoButton, runList, about, actions);
312
509
  }
313
- const figure = h(Svg, { source: figureSvg(view.mood, { still: session.choices.still, title: `${view.title}: ${view.stateLabel}` }),
314
- alt: `${view.title}: ${view.stateLabel}`, width: 200, height: 140, isInteractive: !session.choices.still });
510
+ const scope = view.runId ? JSON.stringify([session.root, view.runId]) : null;
511
+ const quiet = !session.choices.enabled || session.choices.still || session.isHidden || Boolean(view.stale);
512
+ const still = quiet || !scope || ['unreadable', 'idle', 'completionUnconfirmed'].includes(view.figure?.reason.key);
513
+ // Without an assigned run a readable project smiles and keeps the idle motion (blinking) unless the
514
+ // still pose applies; it never gestures. The smile is a static face, so the still pose keeps it.
515
+ const idle = !scope && view.idle === true;
516
+ const idling = idle && !quiet;
517
+ session.figureObservation = observeFigure(session.figureObservation, { scope, figure: view.figure, current: !still });
518
+ const { gate, gesture, sequence } = session.figureObservation ?? {};
519
+ // With every run done the crew member checks the board: a tablet, never a finish flag (no run is shown).
520
+ const figure = h(Svg, { source: figureSvg(view.mood, { still: still && !idling, smile: idle, tablet: idle && view.allDone === true, invite: idle && view.invite === true, resting: view.resting === true, gate, workGate: view.workGate, gesture, sequence }),
521
+ alt: `${view.title}: ${view.stateLabel}`, width: 200, height: 140, isInteractive: !still });
315
522
  // The body is as tall as the pane's body rows less the probed reserve and the content grows, so the
316
523
  // footer sits at the bottom edge; a taller body scrolls with the footer last (live probes of
317
524
  // 2026-10-28: a cell count sizes the body, a percentage does not; SDD-08).
318
525
  return h(Box, { flexDirection: 'column', gap: 1, ...(fits ? { minHeight: rows - BODY_RESERVE } : {}) }, h(Box, { flexDirection: 'column', gap: 1, flexGrow: 1 },
319
526
  h(Box, { flexDirection: 'column', alignItems: 'center' },
320
527
  figure,
321
- h(Text, { color: COLOR[view.mood], size: 'heading', weight: 'bold' }, view.stateLabel),
322
- view.reason ? h(Text, { dimColor: true, wrap: 'truncate-end' }, view.reason) : null),
323
- view.message ? h(Text, {}, view.message) : null,
528
+ // A resting run carries no signal colour: nothing happens and nothing is asked of the person.
529
+ h(Text, { color: view.resting ? undefined : COLOR[view.mood], size: 'heading', weight: 'bold' }, view.stateLabel),
530
+ // The turn block below says what the reason would; without one the reason stays under the state.
531
+ view.reason && !view.turn ? h(Text, { dimColor: true, wrap: 'truncate-end' }, view.reason) : null),
532
+ // An invitation reads as the pane's headline; every other message stays plain.
533
+ view.message ? h(Text, view.invite ? { weight: 'semibold', wrap: 'wrap' } : {}, view.message) : null,
324
534
  view.hint ? h(Text, { dimColor: true }, view.hint) : null,
535
+ view.unreadableHint && view.unreadableHint !== view.message ? h(Text, { color: 'warning' }, view.unreadableHint) : null,
536
+ // The run by its name, with its delivery path and the position on it.
537
+ view.name ? h(Box, { flexDirection: 'column' },
538
+ h(Text, { weight: 'semibold', wrap: 'wrap' }, view.name),
539
+ view.route ? h(Text, { dimColor: true, wrap: 'truncate-end' }, view.route) : null) : null,
540
+ // The run's goal in the chat language, before whose move it is: what an approval is measured against.
541
+ view.goal ? h(Box, { flexDirection: 'column' },
542
+ h(Text, { dimColor: true }, t('fields.objective')),
543
+ h(Text, { wrap: 'wrap' }, view.goal)) : null,
544
+ // Whose move it is, what it is and, for an approval, how it is given.
545
+ view.turn ? h(Box, { flexDirection: 'column', borderStyle: 'single', borderDimColor: true, paddingX: 1 },
546
+ h(Text, { color: TURN_COLOR[view.turn.tone], weight: 'semibold' }, view.turn.who),
547
+ h(Text, { wrap: 'wrap' }, view.turn.what),
548
+ view.turn.how ? h(Text, { dimColor: true, wrap: 'wrap' }, view.turn.how) : null) : null,
325
549
  view.gateBar ? h(Text, { mono: true, wrap: 'truncate-end' }, view.gateBar) : null,
326
- view.runId ? h(Box, { flexDirection: 'column' },
327
- h(Text, { weight: 'semibold', wrap: 'truncate-end' }, view.runId),
328
- view.origin ? h(Text, { dimColor: true }, view.origin) : null) : null,
329
- view.objective ? h(Box, { flexDirection: 'row', gap: 1, alignItems: 'center' },
330
- h(Text, { dimColor: true, wrap: view.isObjectiveExpanded ? 'wrap' : 'truncate-end' }, view.objective),
331
- h(Button, { key: 'objective', plain: true, label: view.isObjectiveExpanded ? t('actions.collapse') : t('actions.expand'),
332
- onPress: press($, async () => { session.isObjectiveExpanded = !session.isObjectiveExpanded; }) })) : null,
333
550
  view.nextStep ? h(Box, { flexDirection: 'column' },
334
551
  h(Text, { dimColor: true }, t('fields.nextStep')),
335
552
  h(Text, {}, view.nextStep)) : null,
553
+ // The (i) and, once opened, the details behind it: a goal that was cut, the gate's purpose, a repeated step.
554
+ infoButton,
555
+ view.isInfoExpanded && view.info?.length ? h(Box, { flexDirection: 'column', gap: 1, borderStyle: 'single', borderDimColor: true, paddingX: 1 },
556
+ ...view.info.map(item => h(Box, { flexDirection: 'column' },
557
+ h(Text, { dimColor: true }, item.label),
558
+ h(Text, { wrap: 'wrap' }, item.text)))) : null,
559
+ ...(view.drift ?? []).map(text => h(Text, { color: 'warning' }, text)),
560
+ view.events ? h(Box, { flexDirection: 'column' },
561
+ h(Text, { dimColor: true }, t('fields.events')),
562
+ ...view.events.map(line => h(Text, { wrap: 'truncate-end' }, line))) : null,
563
+ view.review ? h(Box, { flexDirection: 'column' },
564
+ h(Text, { dimColor: true }, t('fields.material')),
565
+ h(Text, {}, `${view.review.summary} · ${view.review.match}`),
566
+ view.review.preview ? h(Text, { mono: true, dimColor: true, wrap: session.isPreviewExpanded ? 'wrap' : 'truncate-end' },
567
+ session.isPreviewExpanded ? view.review.preview : view.review.preview.split('\n')[0]) : null,
568
+ view.review.preview ? h(Button, { key: 'preview', plain: true, label: session.isPreviewExpanded ? t('actions.collapse') : t('actions.expand'),
569
+ onPress: press($, async () => { session.isPreviewExpanded = !session.isPreviewExpanded; }) }) : null,
570
+ view.review.truncated ? h(Text, { dimColor: true }, view.review.truncated) : null) : null,
571
+ view.eventsHint ? h(Text, { dimColor: true }, view.eventsHint) : null,
336
572
  runList,
573
+ // The run id is a reference for commands, so it stands last and dim.
574
+ view.runId ? h(Box, { flexDirection: 'column' },
575
+ h(Text, { dimColor: true, mono: true, wrap: 'truncate-end' }, view.runId),
576
+ view.origin ? h(Text, { dimColor: true }, view.origin) : null) : null,
337
577
  view.stale ? h(Text, { color: 'warning' }, view.stale) : null,
338
578
  about),
339
579
  actions);
@@ -365,6 +605,7 @@ export const register = on => {
365
605
  // Reading, the status line and the pane stop before the choice is stored, so a failing write
366
606
  // leaves none of them running (CR-F03); the choice is stored even if closing the pane fails.
367
607
  stopRefreshing();
608
+ session.figureObservation = null;
368
609
  silence($);
369
610
  try {
370
611
  await $.ui.close({ id: PANE });
@@ -387,6 +628,9 @@ export const register = on => {
387
628
  // A main-loop turn ends browsing and may name the chat's run (chat-run navigation SDD-02, SDD-04);
388
629
  // the host clock is read beside the event, never before it is passed on (SDD-11).
389
630
  session.isBrowsing = false;
631
+ // Pane entries of events clear at the next main-loop turn (PRD state transitions); an uncertain
632
+ // outcome stays until its run recorded a later operation (CR finding B7).
633
+ session.events = session.events.filter(event => STICKY_KINDS.includes(event.kind));
390
634
  if (!session.isHidden) session.isTurnActive = true;
391
635
  redraw($);
392
636
  const prompt = e.text;
@@ -402,15 +646,17 @@ export const register = on => {
402
646
  if (e.agentId === undefined) {
403
647
  // Cleared on every main-loop completion, also while switched off, so no stale overlay remains.
404
648
  session.isTurnActive = false;
405
- // The read runs after the host has its answer, never inside the hook; a hidden pane keeps
406
- // the status line and toasts current (follow-up SDD-08). The turn's final answer (`e.answer`,
407
- // else the text `next(e)` returned) is matched against that read at the turn's end time, so a
408
- // run created during the turn counts (CR-F05, CR-F06).
649
+ // The check runs after the host has its answer, never inside the hook; a hidden pane keeps
650
+ // the status line and toasts current (follow-up SDD-08). It reads the journal and, on a
651
+ // changed run-file fingerprint, the run view (SDD-007); the turn overlay ends with a redraw
652
+ // either way. The turn's final answer (`e.answer`, else the text `next(e)` returned) is matched
653
+ // at the turn's end time, so a run created during the turn counts (CR-F05, CR-F06).
409
654
  if (session.choices.enabled) {
410
655
  const answer = typeof e.answer === 'string' ? e.answer : answered?.text;
411
656
  void (async () => {
412
657
  const at = await $.clock.now();
413
- await refresh($);
658
+ await pollEvents($);
659
+ if (!(await check($))) redraw($);
414
660
  if (session.choices.enabled && noteMention(answer, at)) { announce($); redraw($); }
415
661
  })().catch(() => {});
416
662
  }
@@ -424,6 +670,7 @@ export const register = on => {
424
670
  // stamps `origin` as `{ kind: 'plugin' | 'person' | 'unload' }`.
425
671
  on('ui.close', { id: PANE }, async ($, e, next) => {
426
672
  try {
673
+ session.figureObservation = null;
427
674
  if (e.origin?.kind === 'person') session.isHidden = true;
428
675
  } catch { /* observation only */ }
429
676
  return next(e);
@@ -432,10 +679,7 @@ export const register = on => {
432
679
  // A logic failure draws a neutral line instead of the panel; it never throws into the host.
433
680
  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
434
681
  try {
435
- return body($, e, buildPanelView({ snapshot: session.snapshot, sessionStartedAt: session.startedAt, selection: selection(),
436
- mention: session.chatMention, isBrowsing: session.isBrowsing,
437
- isTurnActive: session.isTurnActive, registry: session.registry, labels: session.labels, locale: session.locale,
438
- columns: e.props?.bodyColumns ?? Infinity, isObjectiveExpanded: session.isObjectiveExpanded }));
682
+ return body($, e);
439
683
  } catch (error) {
440
684
  const { Text } = $.ui.resolve(e);
441
685
  return h(Text, { dimColor: true }, `AGDF Companion: ${String(error?.message ?? error).slice(0, 200)}`);