@event4u/agent-config 1.13.0 → 1.15.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 (291) hide show
  1. package/.agent-src/commands/agent-handoff.md +4 -1
  2. package/.agent-src/commands/agent-status.md +3 -0
  3. package/.agent-src/commands/agents-audit.md +4 -0
  4. package/.agent-src/commands/agents-cleanup.md +6 -1
  5. package/.agent-src/commands/agents-prepare.md +3 -0
  6. package/.agent-src/commands/analyze-reference-repo.md +4 -0
  7. package/.agent-src/commands/bug-fix.md +7 -3
  8. package/.agent-src/commands/bug-investigate.md +4 -0
  9. package/.agent-src/commands/chat-history-checkpoint.md +126 -0
  10. package/.agent-src/commands/chat-history-clear.md +6 -1
  11. package/.agent-src/commands/chat-history-resume.md +7 -2
  12. package/.agent-src/commands/chat-history.md +7 -2
  13. package/.agent-src/commands/check-current-md.md +137 -0
  14. package/.agent-src/commands/commit-in-chunks.md +118 -0
  15. package/.agent-src/commands/commit.md +4 -0
  16. package/.agent-src/commands/compress.md +37 -2
  17. package/.agent-src/commands/context-create.md +4 -0
  18. package/.agent-src/commands/context-refactor.md +4 -0
  19. package/.agent-src/commands/copilot-agents-init.md +3 -0
  20. package/.agent-src/commands/copilot-agents-optimize.md +3 -0
  21. package/.agent-src/commands/create-pr-description.md +4 -0
  22. package/.agent-src/commands/create-pr.md +4 -0
  23. package/.agent-src/commands/do-and-judge.md +4 -1
  24. package/.agent-src/commands/do-in-steps.md +3 -0
  25. package/.agent-src/commands/e2e-heal.md +4 -0
  26. package/.agent-src/commands/e2e-plan.md +4 -0
  27. package/.agent-src/commands/estimate-ticket.md +4 -1
  28. package/.agent-src/commands/feature-dev.md +4 -0
  29. package/.agent-src/commands/feature-explore.md +4 -0
  30. package/.agent-src/commands/feature-plan.md +4 -0
  31. package/.agent-src/commands/feature-refactor.md +4 -0
  32. package/.agent-src/commands/feature-roadmap.md +6 -0
  33. package/.agent-src/commands/fix-ci.md +4 -0
  34. package/.agent-src/commands/fix-portability.md +5 -2
  35. package/.agent-src/commands/fix-pr-bot-comments.md +4 -0
  36. package/.agent-src/commands/fix-pr-comments.md +4 -0
  37. package/.agent-src/commands/fix-pr-developer-comments.md +4 -0
  38. package/.agent-src/commands/fix-references.md +3 -0
  39. package/.agent-src/commands/fix-seeder.md +4 -0
  40. package/.agent-src/commands/implement-ticket.md +39 -13
  41. package/.agent-src/commands/jira-ticket.md +4 -0
  42. package/.agent-src/commands/judge.md +3 -0
  43. package/.agent-src/commands/memory-add.md +5 -3
  44. package/.agent-src/commands/memory-full.md +5 -2
  45. package/.agent-src/commands/memory-promote.md +7 -6
  46. package/.agent-src/commands/mode.md +3 -0
  47. package/.agent-src/commands/module-create.md +4 -0
  48. package/.agent-src/commands/module-explore.md +4 -0
  49. package/.agent-src/commands/onboard.md +33 -0
  50. package/.agent-src/commands/optimize-agents.md +4 -0
  51. package/.agent-src/commands/optimize-augmentignore.md +12 -0
  52. package/.agent-src/commands/optimize-rtk-filters.md +3 -0
  53. package/.agent-src/commands/optimize-skills.md +4 -0
  54. package/.agent-src/commands/override-create.md +4 -0
  55. package/.agent-src/commands/override-manage.md +4 -0
  56. package/.agent-src/commands/package-reset.md +3 -0
  57. package/.agent-src/commands/package-test.md +3 -0
  58. package/.agent-src/commands/prepare-for-review.md +4 -0
  59. package/.agent-src/commands/project-analyze.md +4 -0
  60. package/.agent-src/commands/project-health.md +4 -0
  61. package/.agent-src/commands/propose-memory.md +6 -8
  62. package/.agent-src/commands/quality-fix.md +4 -0
  63. package/.agent-src/commands/refine-ticket.md +12 -7
  64. package/.agent-src/commands/review-changes.md +39 -8
  65. package/.agent-src/commands/review-routing.md +4 -0
  66. package/.agent-src/commands/roadmap-create.md +18 -0
  67. package/.agent-src/commands/roadmap-execute.md +14 -1
  68. package/.agent-src/commands/rule-compliance-audit.md +4 -0
  69. package/.agent-src/commands/set-cost-profile.md +11 -0
  70. package/.agent-src/commands/sync-agent-settings.md +12 -0
  71. package/.agent-src/commands/sync-gitignore.md +3 -0
  72. package/.agent-src/commands/tests-create.md +4 -0
  73. package/.agent-src/commands/tests-execute.md +6 -3
  74. package/.agent-src/commands/threat-model.md +4 -0
  75. package/.agent-src/commands/update-form-request-messages.md +4 -0
  76. package/.agent-src/commands/upstream-contribute.md +4 -0
  77. package/.agent-src/commands/work.md +161 -0
  78. package/.agent-src/guidelines/agent-infra/engineering-memory-data-format.md +2 -6
  79. package/.agent-src/guidelines/agent-infra/layered-settings.md +0 -1
  80. package/.agent-src/guidelines/agent-infra/memory-access.md +0 -7
  81. package/.agent-src/guidelines/agent-infra/role-contracts.md +2 -4
  82. package/.agent-src/guidelines/agent-infra/self-improvement-pipeline.md +0 -1
  83. package/.agent-src/guidelines/php/patterns/strategy.md +180 -2
  84. package/.agent-src/personas/README.md +0 -1
  85. package/.agent-src/rules/artifact-drafting-protocol.md +7 -2
  86. package/.agent-src/rules/artifact-engagement-recording.md +133 -0
  87. package/.agent-src/rules/ask-when-uncertain.md +18 -13
  88. package/.agent-src/rules/augment-portability.md +64 -37
  89. package/.agent-src/rules/autonomous-execution.md +158 -0
  90. package/.agent-src/rules/chat-history-cadence.md +109 -0
  91. package/.agent-src/rules/chat-history-ownership.md +123 -0
  92. package/.agent-src/rules/chat-history-visibility.md +96 -0
  93. package/.agent-src/rules/cli-output-handling.md +27 -4
  94. package/.agent-src/rules/command-suggestion.md +134 -0
  95. package/.agent-src/rules/commit-policy.md +109 -0
  96. package/.agent-src/rules/direct-answers.md +114 -0
  97. package/.agent-src/rules/docs-sync.md +36 -0
  98. package/.agent-src/rules/downstream-changes.md +10 -9
  99. package/.agent-src/rules/improve-before-implement.md +9 -6
  100. package/.agent-src/rules/language-and-tone.md +85 -6
  101. package/.agent-src/rules/non-destructive-by-default.md +117 -0
  102. package/.agent-src/rules/package-ci-checks.md +4 -0
  103. package/.agent-src/rules/preservation-guard.md +20 -0
  104. package/.agent-src/rules/roadmap-progress-sync.md +159 -27
  105. package/.agent-src/rules/role-mode-adherence.md +1 -1
  106. package/.agent-src/rules/scope-control.md +42 -1
  107. package/.agent-src/rules/size-enforcement.md +2 -3
  108. package/.agent-src/rules/skill-quality.md +3 -8
  109. package/.agent-src/rules/ui-audit-before-build.md +106 -0
  110. package/.agent-src/rules/user-interaction.md +107 -51
  111. package/.agent-src/scripts/update_roadmap_progress.py +73 -9
  112. package/.agent-src/skills/blade-ui/SKILL.md +47 -3
  113. package/.agent-src/skills/command-routing/SKILL.md +32 -0
  114. package/.agent-src/skills/command-writing/SKILL.md +52 -2
  115. package/.agent-src/skills/description-assist/SKILL.md +21 -0
  116. package/.agent-src/skills/estimate-ticket/SKILL.md +0 -1
  117. package/.agent-src/skills/existing-ui-audit/SKILL.md +202 -0
  118. package/.agent-src/skills/fe-design/SKILL.md +78 -61
  119. package/.agent-src/skills/file-editor/SKILL.md +9 -0
  120. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +4 -0
  121. package/.agent-src/skills/flux/SKILL.md +31 -4
  122. package/.agent-src/skills/guideline-writing/SKILL.md +24 -2
  123. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +51 -9
  124. package/.agent-src/skills/livewire/SKILL.md +49 -4
  125. package/.agent-src/skills/md-language-check/SKILL.md +103 -0
  126. package/.agent-src/skills/php-coder/SKILL.md +24 -0
  127. package/.agent-src/skills/react-shadcn-ui/SKILL.md +121 -0
  128. package/.agent-src/skills/refine-prompt/SKILL.md +220 -0
  129. package/.agent-src/skills/refine-ticket/SKILL.md +32 -28
  130. package/.agent-src/skills/roadmap-management/SKILL.md +24 -11
  131. package/.agent-src/skills/rule-writing/SKILL.md +23 -1
  132. package/.agent-src/skills/skill-writing/SKILL.md +3 -5
  133. package/.agent-src/skills/upstream-contribute/SKILL.md +3 -3
  134. package/.agent-src/skills/using-git-worktrees/SKILL.md +3 -1
  135. package/.agent-src/templates/AGENTS.md +24 -6
  136. package/.agent-src/templates/agent-settings.md +149 -0
  137. package/.agent-src/templates/roadmaps.md +11 -4
  138. package/.agent-src/templates/scripts/implement_ticket/__init__.py +63 -26
  139. package/.agent-src/templates/scripts/implement_ticket/__main__.py +8 -2
  140. package/.agent-src/templates/scripts/memory_lookup.py +1 -1
  141. package/.agent-src/templates/scripts/telemetry/__init__.py +42 -0
  142. package/.agent-src/templates/scripts/telemetry/aggregator.py +154 -0
  143. package/.agent-src/templates/scripts/telemetry/boundary.py +171 -0
  144. package/.agent-src/templates/scripts/telemetry/engagement.py +238 -0
  145. package/.agent-src/templates/scripts/telemetry/report_renderer.py +170 -0
  146. package/.agent-src/templates/scripts/telemetry/settings.py +112 -0
  147. package/.agent-src/templates/scripts/telemetry_record.py +166 -0
  148. package/.agent-src/templates/scripts/telemetry_report.py +161 -0
  149. package/.agent-src/templates/scripts/telemetry_status.py +142 -0
  150. package/.agent-src/templates/scripts/work_engine/__init__.py +58 -0
  151. package/.agent-src/templates/scripts/work_engine/__main__.py +9 -0
  152. package/.agent-src/templates/scripts/work_engine/cli.py +195 -0
  153. package/.agent-src/templates/scripts/work_engine/cli_args.py +116 -0
  154. package/.agent-src/templates/scripts/{implement_ticket → work_engine}/delivery_state.py +10 -3
  155. package/.agent-src/templates/scripts/work_engine/directives/__init__.py +33 -0
  156. package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +98 -0
  157. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/analyze.py +1 -1
  158. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/implement.py +3 -3
  159. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/memory.py +2 -2
  160. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/plan.py +2 -2
  161. package/.agent-src/templates/scripts/work_engine/directives/backend/refine.py +396 -0
  162. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/report.py +37 -5
  163. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/test.py +2 -2
  164. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/verify.py +2 -2
  165. package/.agent-src/templates/scripts/work_engine/directives/mixed/__init__.py +116 -0
  166. package/.agent-src/templates/scripts/work_engine/directives/mixed/contract.py +254 -0
  167. package/.agent-src/templates/scripts/work_engine/directives/mixed/stitch.py +229 -0
  168. package/.agent-src/templates/scripts/work_engine/directives/mixed/ui.py +231 -0
  169. package/.agent-src/templates/scripts/work_engine/directives/ui/__init__.py +113 -0
  170. package/.agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +44 -0
  171. package/.agent-src/templates/scripts/work_engine/directives/ui/apply.py +241 -0
  172. package/.agent-src/templates/scripts/work_engine/directives/ui/audit.py +414 -0
  173. package/.agent-src/templates/scripts/work_engine/directives/ui/design.py +335 -0
  174. package/.agent-src/templates/scripts/work_engine/directives/ui/polish.py +510 -0
  175. package/.agent-src/templates/scripts/work_engine/directives/ui/review.py +468 -0
  176. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/__init__.py +119 -0
  177. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.py +37 -0
  178. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.py +165 -0
  179. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.py +66 -0
  180. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/report.py +62 -0
  181. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/test.py +115 -0
  182. package/.agent-src/templates/scripts/work_engine/dispatcher.py +331 -0
  183. package/.agent-src/templates/scripts/work_engine/emitters.py +43 -0
  184. package/.agent-src/templates/scripts/work_engine/errors.py +19 -0
  185. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +76 -0
  186. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +54 -0
  187. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +32 -0
  188. package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +103 -0
  189. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +44 -0
  190. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +42 -0
  191. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +50 -0
  192. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +49 -0
  193. package/.agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.py +53 -0
  194. package/.agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.py +50 -0
  195. package/.agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.py +52 -0
  196. package/.agent-src/templates/scripts/work_engine/hooks/builtin/trace.py +84 -0
  197. package/.agent-src/templates/scripts/work_engine/hooks/context.py +66 -0
  198. package/.agent-src/templates/scripts/work_engine/hooks/events.py +44 -0
  199. package/.agent-src/templates/scripts/work_engine/hooks/exceptions.py +79 -0
  200. package/.agent-src/templates/scripts/work_engine/hooks/registry.py +60 -0
  201. package/.agent-src/templates/scripts/work_engine/hooks/runner.py +73 -0
  202. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +141 -0
  203. package/.agent-src/templates/scripts/work_engine/input_builders.py +163 -0
  204. package/.agent-src/templates/scripts/work_engine/intent/__init__.py +47 -0
  205. package/.agent-src/templates/scripts/work_engine/intent/classify.py +280 -0
  206. package/.agent-src/templates/scripts/work_engine/migration/__init__.py +8 -0
  207. package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +231 -0
  208. package/.agent-src/templates/scripts/{implement_ticket → work_engine}/persona_policy.py +1 -1
  209. package/.agent-src/templates/scripts/work_engine/resolvers/__init__.py +22 -0
  210. package/.agent-src/templates/scripts/work_engine/resolvers/diff.py +106 -0
  211. package/.agent-src/templates/scripts/work_engine/resolvers/file.py +113 -0
  212. package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +90 -0
  213. package/.agent-src/templates/scripts/work_engine/scoring/__init__.py +14 -0
  214. package/.agent-src/templates/scripts/work_engine/scoring/confidence.py +300 -0
  215. package/.agent-src/templates/scripts/work_engine/stack/__init__.py +31 -0
  216. package/.agent-src/templates/scripts/work_engine/stack/detect.py +187 -0
  217. package/.agent-src/templates/scripts/work_engine/state.py +641 -0
  218. package/.agent-src/templates/scripts/work_engine/state_io.py +202 -0
  219. package/.claude-plugin/marketplace.json +105 -2
  220. package/AGENTS.md +38 -8
  221. package/CHANGELOG.md +609 -0
  222. package/README.md +136 -14
  223. package/config/agent-settings.template.yml +45 -0
  224. package/config/gitignore-block.txt +4 -0
  225. package/docs/MIGRATION.md +122 -0
  226. package/docs/architecture.md +111 -35
  227. package/docs/contracts/STABILITY.md +95 -0
  228. package/docs/contracts/adr-chat-history-split.md +132 -0
  229. package/docs/contracts/adr-command-suggestion.md +146 -0
  230. package/docs/contracts/adr-implement-ticket-runtime.md +122 -0
  231. package/docs/contracts/adr-product-ui-track.md +384 -0
  232. package/docs/contracts/adr-prompt-driven-execution.md +187 -0
  233. package/docs/contracts/agent-memory-contract.md +149 -0
  234. package/docs/contracts/artifact-engagement-flow.md +262 -0
  235. package/docs/contracts/command-clusters.md +126 -0
  236. package/docs/contracts/command-suggestion-flow.md +148 -0
  237. package/docs/contracts/implement-ticket-flow.md +628 -0
  238. package/docs/contracts/linear-ai-rules-inclusion.md +143 -0
  239. package/docs/contracts/linear-ai-three-layers.md +131 -0
  240. package/docs/contracts/rule-interactions.md +107 -0
  241. package/docs/contracts/rule-interactions.yml +142 -0
  242. package/docs/contracts/ui-stack-extension.md +236 -0
  243. package/docs/contracts/ui-track-flow.md +338 -0
  244. package/docs/development.md +1 -1
  245. package/docs/getting-started.md +3 -3
  246. package/docs/installation.md +124 -2
  247. package/docs/migrations/commands-1.15.0.md +112 -0
  248. package/docs/showcase.md +204 -0
  249. package/docs/ui-track-mental-model.md +121 -0
  250. package/package.json +1 -1
  251. package/scripts/agent-config +199 -0
  252. package/scripts/audit_cloud_compatibility.py +288 -0
  253. package/scripts/build_cloud_bundle.py +458 -0
  254. package/scripts/build_linear_digest.py +263 -0
  255. package/scripts/chat_history.py +796 -7
  256. package/scripts/check_compression.py +139 -0
  257. package/scripts/check_iron_law_prominence.py +143 -0
  258. package/scripts/check_md_language.py +159 -0
  259. package/scripts/check_portability.py +38 -0
  260. package/scripts/check_public_links.py +185 -0
  261. package/scripts/check_references.py +1 -0
  262. package/scripts/check_reply_consistency.py +140 -0
  263. package/scripts/command_suggester/__init__.py +51 -0
  264. package/scripts/command_suggester/cooldown.py +132 -0
  265. package/scripts/command_suggester/loader.py +70 -0
  266. package/scripts/command_suggester/match.py +180 -0
  267. package/scripts/command_suggester/rank.py +120 -0
  268. package/scripts/command_suggester/render.py +86 -0
  269. package/scripts/command_suggester/sanitize.py +113 -0
  270. package/scripts/command_suggester/settings.py +125 -0
  271. package/scripts/command_suggester/types.py +78 -0
  272. package/scripts/hooks/augment-chat-history.sh +56 -0
  273. package/scripts/install-hooks.sh +67 -0
  274. package/scripts/install.py +150 -33
  275. package/scripts/lint_marketplace.py +27 -0
  276. package/scripts/lint_no_new_atomic_commands.py +179 -0
  277. package/scripts/lint_rule_interactions.py +149 -0
  278. package/scripts/memory_lookup.py +1 -1
  279. package/scripts/migrate_command_suggestions.py +151 -0
  280. package/scripts/release.py +297 -64
  281. package/scripts/schemas/command.schema.json +41 -0
  282. package/scripts/skill_linter.py +81 -0
  283. package/scripts/sync_agent_settings.py +42 -12
  284. package/scripts/update_counts.py +10 -0
  285. package/templates/consumer-settings/augment-cli-hooks.json +54 -0
  286. package/templates/consumer-settings/claude-settings.json +55 -1
  287. package/.agent-src/rules/chat-history.md +0 -171
  288. package/.agent-src/templates/scripts/implement_ticket/cli.py +0 -171
  289. package/.agent-src/templates/scripts/implement_ticket/dispatcher.py +0 -134
  290. package/.agent-src/templates/scripts/implement_ticket/steps/__init__.py +0 -49
  291. package/.agent-src/templates/scripts/implement_ticket/steps/refine.py +0 -140
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python3
2
+ """``./agent-config telemetry:status`` — read-only status report.
3
+
4
+ Prints the current ``telemetry.artifact_engagement`` configuration
5
+ plus log statistics. Safe even when telemetry is disabled — never
6
+ creates the log, never validates, never writes. ``--format json`` is
7
+ the machine-readable contract.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+ from typing import Any
16
+
17
+ from telemetry.engagement import EngagementSchemaError, parse_event
18
+ from telemetry.settings import TelemetrySettings, read_settings
19
+
20
+
21
+ def _last_event_ts(log_path: Path) -> str | None:
22
+ """Return the ``ts`` of the last well-formed event, or None.
23
+
24
+ Reads from the tail to keep the cost bounded on long logs. We
25
+ skip malformed lines silently — Phase 4 surfaces those via the
26
+ aggregator's ``--strict`` flag.
27
+ """
28
+ if not log_path.is_file():
29
+ return None
30
+ try:
31
+ with log_path.open("rb") as fh:
32
+ fh.seek(0, 2) # EOF
33
+ size = fh.tell()
34
+ chunk_size = min(size, 4096)
35
+ fh.seek(size - chunk_size)
36
+ tail = fh.read().decode("utf-8", errors="replace")
37
+ except OSError:
38
+ return None
39
+ for line in reversed(tail.splitlines()):
40
+ line = line.strip()
41
+ if not line:
42
+ continue
43
+ try:
44
+ event = parse_event(line + "\n")
45
+ except EngagementSchemaError:
46
+ continue
47
+ return event.ts
48
+ return None
49
+
50
+
51
+ def _log_stats(log_path: Path) -> dict[str, Any]:
52
+ if not log_path.is_file():
53
+ return {"exists": False, "size_bytes": 0, "line_count": 0}
54
+ try:
55
+ size = log_path.stat().st_size
56
+ with log_path.open("rb") as fh:
57
+ line_count = sum(1 for _ in fh)
58
+ except OSError as exc:
59
+ return {"exists": True, "error": str(exc)}
60
+ return {"exists": True, "size_bytes": size, "line_count": line_count}
61
+
62
+
63
+ def _build_report(settings: TelemetrySettings) -> dict[str, Any]:
64
+ log_path = settings.log_path
65
+ return {
66
+ "enabled": settings.enabled,
67
+ "section_present": settings.section_present,
68
+ "granularity": settings.granularity,
69
+ "record": {
70
+ "consulted": settings.record_consulted,
71
+ "applied": settings.record_applied,
72
+ },
73
+ "log": {
74
+ "path": str(log_path),
75
+ **_log_stats(log_path),
76
+ "last_event_ts": _last_event_ts(log_path),
77
+ },
78
+ }
79
+
80
+
81
+ def _render_text(report: dict[str, Any]) -> str:
82
+ lines: list[str] = []
83
+ enabled = "✅ enabled" if report["enabled"] else "⛔ disabled"
84
+ if not report["section_present"]:
85
+ enabled += " (no telemetry section in .agent-settings.yml — using defaults)"
86
+ lines.append(f" artifact-engagement: {enabled}")
87
+ lines.append(f" granularity: {report['granularity']}")
88
+ rec = report["record"]
89
+ lines.append(
90
+ f" record: consulted={rec['consulted']} "
91
+ f"applied={rec['applied']}"
92
+ )
93
+ log = report["log"]
94
+ lines.append(f" log path: {log['path']}")
95
+ if log.get("exists"):
96
+ if "error" in log:
97
+ lines.append(f" log error: {log['error']}")
98
+ else:
99
+ lines.append(
100
+ f" log size: {log['size_bytes']} bytes "
101
+ f"({log['line_count']} events)"
102
+ )
103
+ if log.get("last_event_ts"):
104
+ lines.append(f" last event ts: {log['last_event_ts']}")
105
+ else:
106
+ lines.append(" log: not yet created")
107
+ return "\n".join(lines)
108
+
109
+
110
+ def main(argv: list[str] | None = None) -> int:
111
+ parser = argparse.ArgumentParser(
112
+ prog="agent-config telemetry:status",
113
+ description=(
114
+ "Print the artifact-engagement telemetry status. Read-only "
115
+ "— never creates the log, never modifies settings."
116
+ ),
117
+ )
118
+ parser.add_argument("--format", choices=("text", "json"), default="text")
119
+ parser.add_argument(
120
+ "--settings",
121
+ type=Path,
122
+ default=Path(".agent-settings.yml"),
123
+ help="Override settings path (tests).",
124
+ )
125
+ args = parser.parse_args(argv)
126
+
127
+ try:
128
+ settings = read_settings(args.settings)
129
+ except OSError as exc:
130
+ print(f"❌ cannot read settings: {exc}", file=sys.stderr)
131
+ return 2
132
+
133
+ report = _build_report(settings)
134
+ if args.format == "json":
135
+ print(json.dumps(report, sort_keys=True, indent=2))
136
+ else:
137
+ print(_render_text(report))
138
+ return 0
139
+
140
+
141
+ if __name__ == "__main__":
142
+ raise SystemExit(main())
@@ -0,0 +1,58 @@
1
+ """``work_engine`` — universal execution engine (R1).
2
+
3
+ The package owns the linear step dispatcher that drives
4
+ ``/implement-ticket`` and any future intent-routed flow. Phase 2 added
5
+ the persistent ``state`` schema and the v0→v1 migration; Phase 3 moves
6
+ the dispatcher, CLI and step modules over from the legacy
7
+ ``implement_ticket`` package — which is now a thin compatibility shim
8
+ that re-exports from here with a ``DeprecationWarning``.
9
+
10
+ Architectural constraints (from
11
+ ``docs/contracts/adr-implement-ticket-runtime.md`` and
12
+ ``docs/contracts/implement-ticket-flow.md``):
13
+
14
+ - Runtime is Python 3.10+.
15
+ - The dispatcher is linear, not a DAG. Eight fixed steps, fixed order.
16
+ - ``DeliveryState`` is the only object shared between steps — no
17
+ hidden state, no side channels.
18
+ - Every step terminates in ``success | blocked | partial``. ``blocked``
19
+ and ``partial`` halt the flow and surface numbered questions.
20
+ - The dispatcher never calls git, writes commits, or opens PRs.
21
+ """
22
+ from __future__ import annotations
23
+
24
+ from .delivery_state import (
25
+ AGENT_DIRECTIVE_PREFIX,
26
+ DeliveryState,
27
+ Outcome,
28
+ Step,
29
+ StepResult,
30
+ agent_directive,
31
+ is_agent_directive,
32
+ )
33
+ from .cli import DEFAULT_STATE_FILE, main
34
+ from .dispatcher import STEP_ORDER, dispatch
35
+ from .persona_policy import (
36
+ DEFAULT_PERSONA,
37
+ PersonaPolicy,
38
+ known_personas,
39
+ resolve_policy,
40
+ )
41
+
42
+ __all__ = [
43
+ "AGENT_DIRECTIVE_PREFIX",
44
+ "DEFAULT_PERSONA",
45
+ "DEFAULT_STATE_FILE",
46
+ "DeliveryState",
47
+ "Outcome",
48
+ "PersonaPolicy",
49
+ "STEP_ORDER",
50
+ "Step",
51
+ "StepResult",
52
+ "agent_directive",
53
+ "dispatch",
54
+ "is_agent_directive",
55
+ "known_personas",
56
+ "main",
57
+ "resolve_policy",
58
+ ]
@@ -0,0 +1,9 @@
1
+ """Module entry point — lets ``python3 -m implement_ticket`` run the CLI."""
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+
6
+ from .cli import main
7
+
8
+ if __name__ == "__main__":
9
+ sys.exit(main())
@@ -0,0 +1,195 @@
1
+ """Command-line entry point for ``/implement-ticket``.
2
+
3
+ Minimal Option-A transport: the script loads a persisted state file,
4
+ runs the dispatcher once, writes the updated state back, and prints
5
+ either the delivery report (on SUCCESS) or the halt surface —
6
+ directive plus numbered questions — on BLOCKED/PARTIAL.
7
+
8
+ The script never edits code, runs tests, or opens pull requests.
9
+ All of that is delegated to the agent via ``@agent-directive:``
10
+ markers per
11
+ ``docs/contracts/implement-ticket-flow.md#agent-directives``. The
12
+ agent executes the directive, writes the resulting slice back to
13
+ the state file, and re-invokes this script to resume.
14
+
15
+ Wire format (R1 P4 S1, Option A2): the CLI accepts both the legacy
16
+ v0 wire format (``{"ticket": …, "persona": …}``) and the v1 schema
17
+ (``{"version": 1, "input": {"kind": "ticket", "data": …}}``). Loaded
18
+ state is wrapped in :class:`work_engine.state.WorkState` for the
19
+ boundary; before dispatch it is projected into a ``DeliveryState``
20
+ the step handlers understand. After dispatch the mutations are
21
+ mirrored back, and the file is rewritten in the **same** wire format
22
+ it was loaded with — Goldens captured against v0 stay v0 byte-for-
23
+ byte, while flows that already store v1 round-trip as v1.
24
+
25
+ Layout (post P2.3 of ``road-to-post-pr29-optimize.md``): this file
26
+ is a thin orchestrator. The argument parser, state I/O, file-input
27
+ builders, hook bootstrap, and stdout/stderr emitters live in their
28
+ own leaf modules under ``work_engine`` — see ``cli_args``,
29
+ ``state_io``, ``input_builders``, ``hook_bootstrap``, ``emitters``,
30
+ ``errors``. Public names (``main``, ``DEFAULT_STATE_FILE``) and the
31
+ private monkeypatch surface (``_build_hook_registry``,
32
+ ``_CLIError``, ``_load_or_build``, …) are re-exported here so
33
+ existing imports and patch targets continue to resolve.
34
+
35
+ Exit codes:
36
+
37
+ - ``0`` — flow reached SUCCESS; ``state.report`` printed.
38
+ - ``1`` — flow halted BLOCKED; halt surface printed on stdout, the
39
+ state file carries the updated ``outcomes`` and ``questions`` so
40
+ the agent can resume.
41
+ - ``2`` — argument or I/O error (ticket file missing, JSON parse
42
+ failure, etc.). The state file is *not* written in this case.
43
+ """
44
+ from __future__ import annotations
45
+
46
+ import sys
47
+ from pathlib import Path
48
+ from typing import Sequence
49
+
50
+ from .cli_args import (
51
+ DEFAULT_STATE_FILE,
52
+ LEGACY_STATE_FILE,
53
+ _build_parser,
54
+ _FMT_V0,
55
+ _FMT_V1,
56
+ )
57
+ from .delivery_state import Outcome
58
+ from .dispatcher import (
59
+ assert_kind_supported,
60
+ dispatch,
61
+ load_directive_set,
62
+ select_directive_set,
63
+ )
64
+ from .emitters import _emit, _emit_halt
65
+ from .errors import _CLIError
66
+ from .hook_bootstrap import _build_hook_registry, _register_chat_history_hooks
67
+ from .hooks import HookContext, HookEvent, HookRunner
68
+ from .input_builders import (
69
+ _build_from_diff_file,
70
+ _build_from_file_file,
71
+ _build_from_prompt_file,
72
+ _load_or_build,
73
+ )
74
+ from .state_io import (
75
+ _load,
76
+ _maybe_raise_legacy_hint,
77
+ _read_json,
78
+ _save,
79
+ _sync_back,
80
+ _to_delivery,
81
+ _to_v0_dict,
82
+ )
83
+
84
+
85
+ def main(argv: Sequence[str] | None = None) -> int:
86
+ """Run one dispatch cycle against the persisted state.
87
+
88
+ ``argv`` is taken as-is; pass ``None`` to fall back to
89
+ ``sys.argv[1:]`` (the usual entry-point contract).
90
+ """
91
+ parser = _build_parser()
92
+ args = parser.parse_args(argv)
93
+ state_file: Path = args.state_file
94
+
95
+ runner = HookRunner(_build_hook_registry(args))
96
+
97
+ halt = runner.emit(
98
+ HookEvent.BEFORE_LOAD,
99
+ HookContext(state_file=state_file, args=args),
100
+ )
101
+ if halt is not None:
102
+ return _emit_halt(halt)
103
+
104
+ try:
105
+ work, fmt = _load_or_build(state_file, args)
106
+ except _CLIError as exc:
107
+ print(f"error: {exc}", file=sys.stderr)
108
+ return 2
109
+
110
+ halt = runner.emit(
111
+ HookEvent.AFTER_LOAD,
112
+ HookContext(state_file=state_file, work=work, fmt=fmt, args=args),
113
+ )
114
+ if halt is not None:
115
+ return _emit_halt(halt)
116
+
117
+ try:
118
+ set_name = select_directive_set(work)
119
+ assert_kind_supported(work.input.kind, set_name)
120
+ steps = load_directive_set(set_name)
121
+ except (ValueError, NotImplementedError) as exc:
122
+ print(f"error: {exc}", file=sys.stderr)
123
+ return 2
124
+
125
+ delivery = _to_delivery(work)
126
+
127
+ halt = runner.emit(
128
+ HookEvent.BEFORE_DISPATCH,
129
+ HookContext(work=work, delivery=delivery, set_name=set_name, args=args),
130
+ )
131
+ if halt is not None:
132
+ return _emit_halt(halt)
133
+
134
+ final, halting = dispatch(delivery, steps, hooks=runner)
135
+
136
+ halt = runner.emit(
137
+ HookEvent.AFTER_DISPATCH,
138
+ HookContext(
139
+ work=work,
140
+ delivery=delivery,
141
+ final=final,
142
+ halting=halting,
143
+ args=args,
144
+ ),
145
+ )
146
+ if halt is not None:
147
+ return _emit_halt(halt)
148
+
149
+ _sync_back(work, delivery)
150
+
151
+ halt = runner.emit(
152
+ HookEvent.BEFORE_SAVE,
153
+ HookContext(work=work, delivery=delivery, fmt=fmt, args=args),
154
+ )
155
+ if halt is not None:
156
+ return _emit_halt(halt)
157
+
158
+ _save(state_file, work, fmt)
159
+
160
+ halt = runner.emit(
161
+ HookEvent.AFTER_SAVE,
162
+ HookContext(work=work, state_file=state_file, fmt=fmt, args=args),
163
+ )
164
+ if halt is not None:
165
+ # State is already on disk; exit 2 still per the P3 branch table.
166
+ return _emit_halt(halt)
167
+
168
+ _emit(work, final, halting)
169
+ return 0 if final is Outcome.SUCCESS else 1
170
+
171
+
172
+ __all__ = [
173
+ "DEFAULT_STATE_FILE",
174
+ "LEGACY_STATE_FILE",
175
+ "_CLIError",
176
+ "_FMT_V0",
177
+ "_FMT_V1",
178
+ "_build_from_diff_file",
179
+ "_build_from_file_file",
180
+ "_build_from_prompt_file",
181
+ "_build_hook_registry",
182
+ "_build_parser",
183
+ "_emit",
184
+ "_emit_halt",
185
+ "_load",
186
+ "_load_or_build",
187
+ "_maybe_raise_legacy_hint",
188
+ "_read_json",
189
+ "_register_chat_history_hooks",
190
+ "_save",
191
+ "_sync_back",
192
+ "_to_delivery",
193
+ "_to_v0_dict",
194
+ "main",
195
+ ]
@@ -0,0 +1,116 @@
1
+ """Argument parser and state-file constants for the CLI entry point.
2
+
3
+ Extracted from ``cli.py`` in P2.3 of
4
+ ``road-to-post-pr29-optimize.md``. Behaviour-preserving: the parser
5
+ shape, default values, help strings and exit-code semantics are
6
+ byte-identical to the pre-split version. The constants moved here
7
+ so the parser default and the legacy-file detector both reference
8
+ a single source of truth.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ from pathlib import Path
14
+
15
+ DEFAULT_STATE_FILE = Path(".work-state.json")
16
+ """State file used when ``--state-file`` is not passed.
17
+
18
+ Renamed from ``.implement-ticket-state.json`` in 1.15.0 alongside the
19
+ ``implement_ticket → work_engine`` package move. The legacy filename is
20
+ still recognised on load (see :data:`LEGACY_STATE_FILE` below) so that
21
+ existing checkouts surface a clear migration message instead of a
22
+ silent "no state file" error."""
23
+
24
+ LEGACY_STATE_FILE = Path(".implement-ticket-state.json")
25
+ """Pre-1.15.0 default state file. Detected only as a migration hint;
26
+ never written to. See ``docs/MIGRATION.md``."""
27
+
28
+ _FMT_V0 = "v0"
29
+ _FMT_V1 = "v1"
30
+ """Wire-format markers carried alongside the loaded :class:`WorkState`.
31
+
32
+ Format-preserving roundtrip: ``_load`` records which shape it parsed,
33
+ ``_save`` rewrites in that same shape. v0 in → v0 out (Goldens stay
34
+ byte-equal); v1 in → v1 out (future flows produced by the migration
35
+ tool or a fresh v1 init keep their envelope fields)."""
36
+
37
+
38
+ def _build_parser() -> argparse.ArgumentParser:
39
+ parser = argparse.ArgumentParser(
40
+ prog="implement-ticket",
41
+ description="Run one dispatch cycle of the /implement-ticket flow.",
42
+ )
43
+ parser.add_argument(
44
+ "--state-file",
45
+ type=Path,
46
+ default=DEFAULT_STATE_FILE,
47
+ help=f"Path to persisted state JSON (default: {DEFAULT_STATE_FILE}).",
48
+ )
49
+ parser.add_argument(
50
+ "--ticket-file",
51
+ type=Path,
52
+ default=None,
53
+ help="JSON file carrying the ticket payload; used only when the "
54
+ "state file does not exist yet.",
55
+ )
56
+ parser.add_argument(
57
+ "--prompt-file",
58
+ type=Path,
59
+ default=None,
60
+ help="Plain-text file carrying the raw user prompt; builds an "
61
+ "input.kind='prompt' envelope. Mutually exclusive with "
62
+ "--ticket-file. Used only when the state file does not exist yet.",
63
+ )
64
+ parser.add_argument(
65
+ "--diff-file",
66
+ type=Path,
67
+ default=None,
68
+ help="Plain-text file carrying a unified diff payload; builds an "
69
+ "input.kind='diff' envelope routed through the UI-improve "
70
+ "directive set. Mutually exclusive with --ticket-file / "
71
+ "--prompt-file / --file-file. Used only when the state file does "
72
+ "not exist yet.",
73
+ )
74
+ parser.add_argument(
75
+ "--file-file",
76
+ type=Path,
77
+ default=None,
78
+ help="Plain-text file carrying a single path reference (one line); "
79
+ "builds an input.kind='file' envelope routed through the UI-improve "
80
+ "directive set. Mutually exclusive with --ticket-file / "
81
+ "--prompt-file / --diff-file. Used only when the state file does "
82
+ "not exist yet.",
83
+ )
84
+ parser.add_argument(
85
+ "--persona",
86
+ type=str,
87
+ default=None,
88
+ help="Persona name (senior-engineer | qa | advisory). Only honoured "
89
+ "when the state file does not exist yet; ignored on resume so a "
90
+ "mid-flight persona switch cannot silently change behaviour.",
91
+ )
92
+ parser.add_argument(
93
+ "--no-hooks",
94
+ action="store_true",
95
+ default=False,
96
+ help="Disable every lifecycle hook for this run. Use in golden-"
97
+ "replay test harnesses so a future settings change cannot "
98
+ "silently invalidate captured outputs.",
99
+ )
100
+ parser.add_argument(
101
+ "--hooks-config",
102
+ type=Path,
103
+ default=None,
104
+ help="Override the path to the agent-settings file used to resolve "
105
+ "the hooks.* block. Defaults to ./.agent-settings.yml.",
106
+ )
107
+ return parser
108
+
109
+
110
+ __all__ = [
111
+ "DEFAULT_STATE_FILE",
112
+ "LEGACY_STATE_FILE",
113
+ "_FMT_V0",
114
+ "_FMT_V1",
115
+ "_build_parser",
116
+ ]
@@ -1,6 +1,6 @@
1
1
  """``DeliveryState`` — the only object shared between orchestrator steps.
2
2
 
3
- The shape mirrors ``agents/contexts/implement-ticket-flow.md``. No step
3
+ The shape mirrors ``docs/contracts/implement-ticket-flow.md``. No step
4
4
  may invent fields not declared here; extensions require a roadmap
5
5
  amendment plus a flow-contract update.
6
6
 
@@ -59,7 +59,7 @@ class DeliveryState:
59
59
  """Canonical state passed between orchestrator steps.
60
60
 
61
61
  Field order matches the table in
62
- ``agents/contexts/implement-ticket-flow.md``. Mutable defaults use
62
+ ``docs/contracts/implement-ticket-flow.md``. Mutable defaults use
63
63
  ``field(default_factory=...)`` so every instance owns its own
64
64
  containers — a single shared list across runs would be a
65
65
  cross-run contamination hazard for the metrics pipeline.
@@ -75,6 +75,13 @@ class DeliveryState:
75
75
  outcomes: dict[str, str] = field(default_factory=dict)
76
76
  questions: list[str] = field(default_factory=list)
77
77
  report: str = ""
78
+ ui_audit: dict[str, Any] | None = None
79
+ ui_design: dict[str, Any] | None = None
80
+ ui_review: dict[str, Any] | None = None
81
+ ui_polish: dict[str, Any] | None = None
82
+ contract: dict[str, Any] | None = None
83
+ stitch: dict[str, Any] | None = None
84
+ stack: dict[str, Any] | None = None
78
85
 
79
86
 
80
87
  Step = Callable[[DeliveryState], StepResult]
@@ -96,7 +103,7 @@ skill; the user-facing numbered options follow on subsequent lines.
96
103
 
97
104
  The prefix is public contract: changing it breaks every agent that
98
105
  has learned to recognise it. See
99
- ``agents/contexts/implement-ticket-flow.md#agent-directives``.
106
+ ``docs/contracts/implement-ticket-flow.md#agent-directives``.
100
107
  """
101
108
 
102
109
 
@@ -0,0 +1,33 @@
1
+ """Directive-set bundles consumed by the dispatcher.
2
+
3
+ A *directive set* is a coherent group of step handlers (refine,
4
+ memory, analyze, plan, implement, test, verify, report) tuned for a
5
+ particular kind of work — backend coding, UI work, mixed front+back
6
+ work, and so on. The dispatcher selects exactly one set per cycle
7
+ (see ``dispatcher.select_directive_set``) and walks its eight steps
8
+ in the canonical order.
9
+
10
+ Each set is a Python sub-package exposing a single function::
11
+
12
+ def get_steps() -> Mapping[str, Step]:
13
+ '''Return the {step_name: handler} mapping the dispatcher walks.'''
14
+
15
+ The mapping must cover every entry in :data:`dispatcher.STEP_ORDER`;
16
+ incomplete bundles raise ``KeyError`` at dispatch time.
17
+
18
+ Roadmap status (R1 Phase 4):
19
+
20
+ - ``backend`` — fully implemented; landing in Step 3 of this phase.
21
+ - ``ui`` — stub; lands in Roadmap 3 (``road-to-product-ui-track.md``).
22
+ - ``ui_trivial`` — stub; lands in Roadmap 3 V2.
23
+ - ``mixed`` — stub; lands in Roadmap 3.
24
+
25
+ The schema (``state.KNOWN_DIRECTIVE_SETS``) carries the *external*
26
+ names ``ui``, ``ui-trivial``, ``mixed``; the directory layout uses
27
+ underscores (``ui_trivial``) because Python packages cannot contain
28
+ hyphens. The dispatcher's loader is the single place that translates
29
+ between the two.
30
+ """
31
+ from __future__ import annotations
32
+
33
+ __all__: list[str] = []
@@ -0,0 +1,98 @@
1
+ """Backend directive set — step handlers for the backend-coding flow.
2
+
3
+ Each module exposes a single ``run`` callable that matches the
4
+ ``Step`` protocol defined in ``...delivery_state``. The dispatcher
5
+ wires them into the ``STEP_ORDER`` mapping at call time; nothing in
6
+ this package imports handlers eagerly, so a partial wiring during
7
+ development is caught by the dispatcher's missing-step check rather
8
+ than by an import-time failure.
9
+
10
+ This is the first concrete entry in the
11
+ :mod:`work_engine.directives` package. R1 Phase 4 Step 3 moved the
12
+ handlers here from the original ``work_engine.steps`` location so
13
+ the upcoming generalized dispatcher (Step 2) can select between
14
+ multiple directive sets uniformly via :func:`get_steps`. The
15
+ external behavior — flow order, ambiguity surfaces, halt-points —
16
+ is unchanged.
17
+
18
+ The deterministic gates (``refine``, ``memory``, ``analyze``)
19
+ validate upstream state; the delegation gates (``plan``,
20
+ ``implement``, ``test``, ``verify``) halt with
21
+ ``@agent-directive:`` markers so the orchestrator can invoke the
22
+ matching skill and resume. ``report`` renders the delivery Markdown
23
+ once everything else has succeeded. See
24
+ ``agents/roadmaps/road-to-implement-ticket.md`` for the shipping
25
+ order and ``docs/contracts/implement-ticket-flow.md`` for the
26
+ slice contracts each handler writes to.
27
+ """
28
+ from __future__ import annotations
29
+
30
+ from collections.abc import Mapping
31
+
32
+ from ...delivery_state import Step
33
+ from . import analyze, implement, memory, plan, refine, report, test, verify
34
+
35
+ DIRECTIVE_SET_NAME = "backend"
36
+ """External name carried in ``state.directive_set`` for this set."""
37
+
38
+ SUPPORTED_KINDS: tuple[str, ...] = ("ticket", "prompt")
39
+ """Input kinds this directive set knows how to handle.
40
+
41
+ Read by :func:`work_engine.dispatcher.assert_kind_supported` before the
42
+ loop starts. The schema's :data:`work_engine.state.KNOWN_INPUT_KINDS` is
43
+ the *envelope* whitelist (what is accepted on disk); ``SUPPORTED_KINDS``
44
+ is the *capability* whitelist (what this set can actually drive end to
45
+ end).
46
+
47
+ R1 only carried ``ticket``. R2 Phase 3 Step 3 added ``prompt`` once the
48
+ ``refine`` step learned to detect prompt envelopes (presence of ``raw``
49
+ key in ``state.ticket``), delegate to the ``refine-prompt`` skill on
50
+ the first pass, and route the resulting confidence band into
51
+ ``SUCCESS`` / ``PARTIAL`` / ``BLOCKED`` per
52
+ ``agents/roadmaps/archive/road-to-prompt-driven-execution.md`` Phase 3."""
53
+
54
+ _STEPS = (refine, memory, analyze, plan, implement, test, verify, report)
55
+
56
+
57
+ def all_ambiguities() -> dict[str, tuple[dict[str, str], ...]]:
58
+ """Return `{step_name: AMBIGUITIES}` for every step in flow order.
59
+
60
+ Used by documentation generators and the ``test_ambiguity_coverage``
61
+ suite to prove every step explicitly declares what can surface a
62
+ ``BLOCKED`` outcome. Steps that always succeed (``memory``,
63
+ ``report``) return an empty tuple — declared intent, not an
64
+ omission.
65
+ """
66
+ return {step.__name__.rsplit(".", 1)[-1]: step.AMBIGUITIES for step in _STEPS}
67
+
68
+
69
+ def get_steps() -> Mapping[str, Step]:
70
+ """Return the ``{step_name: handler}`` mapping the dispatcher walks.
71
+
72
+ Each value is the module-level ``run`` callable matching the
73
+ :data:`work_engine.delivery_state.Step` protocol —
74
+ ``Callable[[DeliveryState], StepResult]`` — exactly what
75
+ :func:`work_engine.dispatcher.dispatch` calls. Order of insertion
76
+ matches the canonical backend flow (refine → memory → analyze →
77
+ plan → implement → test → verify → report); the dispatcher's own
78
+ ``STEP_ORDER`` is the single source of truth for *which* steps
79
+ exist, but the directive set is the single source of truth for
80
+ *how* each one runs.
81
+ """
82
+ return {step.__name__.rsplit(".", 1)[-1]: step.run for step in _STEPS}
83
+
84
+
85
+ __all__ = [
86
+ "DIRECTIVE_SET_NAME",
87
+ "SUPPORTED_KINDS",
88
+ "all_ambiguities",
89
+ "analyze",
90
+ "get_steps",
91
+ "implement",
92
+ "memory",
93
+ "plan",
94
+ "refine",
95
+ "report",
96
+ "test",
97
+ "verify",
98
+ ]