@event4u/agent-config 1.12.0 → 1.14.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 (260) hide show
  1. package/.agent-src/commands/agent-handoff.md +3 -0
  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 +5 -1
  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 +5 -0
  11. package/.agent-src/commands/chat-history-resume.md +5 -0
  12. package/.agent-src/commands/chat-history.md +5 -0
  13. package/.agent-src/commands/check-current-md.md +126 -0
  14. package/.agent-src/commands/commit-in-chunks.md +98 -0
  15. package/.agent-src/commands/commit.md +4 -0
  16. package/.agent-src/commands/compress.md +3 -0
  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 +3 -0
  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 +24 -0
  50. package/.agent-src/commands/optimize-agents.md +4 -0
  51. package/.agent-src/commands/optimize-augmentignore.md +3 -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 +4 -1
  64. package/.agent-src/commands/review-changes.md +4 -0
  65. package/.agent-src/commands/review-routing.md +4 -0
  66. package/.agent-src/commands/roadmap-create.md +7 -0
  67. package/.agent-src/commands/roadmap-execute.md +12 -1
  68. package/.agent-src/commands/rule-compliance-audit.md +4 -0
  69. package/.agent-src/commands/set-cost-profile.md +3 -0
  70. package/.agent-src/commands/sync-agent-settings.md +3 -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 +4 -0
  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 +8 -0
  89. package/.agent-src/rules/autonomous-execution.md +158 -0
  90. package/.agent-src/rules/chat-history.md +147 -118
  91. package/.agent-src/rules/cli-output-handling.md +26 -3
  92. package/.agent-src/rules/command-suggestion.md +133 -0
  93. package/.agent-src/rules/commit-policy.md +99 -0
  94. package/.agent-src/rules/direct-answers.md +114 -0
  95. package/.agent-src/rules/docs-sync.md +36 -0
  96. package/.agent-src/rules/downstream-changes.md +10 -9
  97. package/.agent-src/rules/improve-before-implement.md +9 -6
  98. package/.agent-src/rules/language-and-tone.md +81 -6
  99. package/.agent-src/rules/non-destructive-by-default.md +117 -0
  100. package/.agent-src/rules/package-ci-checks.md +4 -0
  101. package/.agent-src/rules/preservation-guard.md +20 -0
  102. package/.agent-src/rules/roadmap-progress-sync.md +103 -30
  103. package/.agent-src/rules/scope-control.md +42 -1
  104. package/.agent-src/rules/size-enforcement.md +1 -3
  105. package/.agent-src/rules/skill-quality.md +3 -8
  106. package/.agent-src/rules/ui-audit-before-build.md +106 -0
  107. package/.agent-src/rules/user-interaction.md +81 -3
  108. package/.agent-src/scripts/update_roadmap_progress.py +48 -6
  109. package/.agent-src/skills/blade-ui/SKILL.md +30 -5
  110. package/.agent-src/skills/command-routing/SKILL.md +32 -0
  111. package/.agent-src/skills/command-writing/SKILL.md +41 -2
  112. package/.agent-src/skills/description-assist/SKILL.md +21 -0
  113. package/.agent-src/skills/estimate-ticket/SKILL.md +0 -1
  114. package/.agent-src/skills/existing-ui-audit/SKILL.md +187 -0
  115. package/.agent-src/skills/fe-design/SKILL.md +72 -60
  116. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +4 -0
  117. package/.agent-src/skills/flux/SKILL.md +31 -4
  118. package/.agent-src/skills/guideline-writing/SKILL.md +24 -2
  119. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +51 -9
  120. package/.agent-src/skills/livewire/SKILL.md +30 -4
  121. package/.agent-src/skills/md-language-check/SKILL.md +103 -0
  122. package/.agent-src/skills/php-coder/SKILL.md +24 -0
  123. package/.agent-src/skills/react-shadcn-ui/SKILL.md +121 -0
  124. package/.agent-src/skills/refine-prompt/SKILL.md +220 -0
  125. package/.agent-src/skills/refine-ticket/SKILL.md +2 -4
  126. package/.agent-src/skills/roadmap-management/SKILL.md +10 -3
  127. package/.agent-src/skills/rule-writing/SKILL.md +23 -1
  128. package/.agent-src/skills/skill-writing/SKILL.md +1 -3
  129. package/.agent-src/skills/upstream-contribute/SKILL.md +1 -1
  130. package/.agent-src/skills/using-git-worktrees/SKILL.md +3 -1
  131. package/.agent-src/templates/AGENTS.md +24 -6
  132. package/.agent-src/templates/agent-settings.md +149 -0
  133. package/.agent-src/templates/github-workflows/roadmap-progress-check.yml +63 -0
  134. package/.agent-src/templates/hooks/pre-commit-roadmap-progress +60 -0
  135. package/.agent-src/templates/roadmaps.md +8 -2
  136. package/.agent-src/templates/scripts/implement_ticket/__init__.py +63 -26
  137. package/.agent-src/templates/scripts/implement_ticket/__main__.py +8 -2
  138. package/.agent-src/templates/scripts/memory_lookup.py +382 -21
  139. package/.agent-src/templates/scripts/memory_status.py +110 -9
  140. package/.agent-src/templates/scripts/telemetry/__init__.py +42 -0
  141. package/.agent-src/templates/scripts/telemetry/aggregator.py +154 -0
  142. package/.agent-src/templates/scripts/telemetry/boundary.py +171 -0
  143. package/.agent-src/templates/scripts/telemetry/engagement.py +238 -0
  144. package/.agent-src/templates/scripts/telemetry/report_renderer.py +170 -0
  145. package/.agent-src/templates/scripts/telemetry/settings.py +112 -0
  146. package/.agent-src/templates/scripts/telemetry_record.py +166 -0
  147. package/.agent-src/templates/scripts/telemetry_report.py +161 -0
  148. package/.agent-src/templates/scripts/telemetry_status.py +142 -0
  149. package/.agent-src/templates/scripts/work_engine/__init__.py +58 -0
  150. package/.agent-src/templates/scripts/work_engine/__main__.py +9 -0
  151. package/.agent-src/templates/scripts/work_engine/cli.py +592 -0
  152. package/.agent-src/templates/scripts/{implement_ticket → work_engine}/delivery_state.py +7 -0
  153. package/.agent-src/templates/scripts/work_engine/directives/__init__.py +33 -0
  154. package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +98 -0
  155. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/analyze.py +1 -1
  156. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/implement.py +2 -2
  157. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/memory.py +1 -1
  158. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/plan.py +1 -1
  159. package/.agent-src/templates/scripts/work_engine/directives/backend/refine.py +396 -0
  160. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/report.py +36 -4
  161. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/test.py +2 -2
  162. package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/verify.py +2 -2
  163. package/.agent-src/templates/scripts/work_engine/directives/mixed/__init__.py +116 -0
  164. package/.agent-src/templates/scripts/work_engine/directives/mixed/contract.py +254 -0
  165. package/.agent-src/templates/scripts/work_engine/directives/mixed/stitch.py +229 -0
  166. package/.agent-src/templates/scripts/work_engine/directives/mixed/ui.py +231 -0
  167. package/.agent-src/templates/scripts/work_engine/directives/ui/__init__.py +113 -0
  168. package/.agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +44 -0
  169. package/.agent-src/templates/scripts/work_engine/directives/ui/apply.py +241 -0
  170. package/.agent-src/templates/scripts/work_engine/directives/ui/audit.py +414 -0
  171. package/.agent-src/templates/scripts/work_engine/directives/ui/design.py +335 -0
  172. package/.agent-src/templates/scripts/work_engine/directives/ui/polish.py +510 -0
  173. package/.agent-src/templates/scripts/work_engine/directives/ui/review.py +468 -0
  174. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/__init__.py +119 -0
  175. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.py +37 -0
  176. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.py +165 -0
  177. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.py +66 -0
  178. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/report.py +62 -0
  179. package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/test.py +115 -0
  180. package/.agent-src/templates/scripts/work_engine/dispatcher.py +331 -0
  181. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +54 -0
  182. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +32 -0
  183. package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +103 -0
  184. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +44 -0
  185. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +42 -0
  186. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +50 -0
  187. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +49 -0
  188. package/.agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.py +53 -0
  189. package/.agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.py +50 -0
  190. package/.agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.py +52 -0
  191. package/.agent-src/templates/scripts/work_engine/hooks/builtin/trace.py +84 -0
  192. package/.agent-src/templates/scripts/work_engine/hooks/context.py +66 -0
  193. package/.agent-src/templates/scripts/work_engine/hooks/events.py +44 -0
  194. package/.agent-src/templates/scripts/work_engine/hooks/exceptions.py +79 -0
  195. package/.agent-src/templates/scripts/work_engine/hooks/registry.py +60 -0
  196. package/.agent-src/templates/scripts/work_engine/hooks/runner.py +73 -0
  197. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +141 -0
  198. package/.agent-src/templates/scripts/work_engine/intent/__init__.py +47 -0
  199. package/.agent-src/templates/scripts/work_engine/intent/classify.py +280 -0
  200. package/.agent-src/templates/scripts/work_engine/migration/__init__.py +8 -0
  201. package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +199 -0
  202. package/.agent-src/templates/scripts/work_engine/resolvers/__init__.py +22 -0
  203. package/.agent-src/templates/scripts/work_engine/resolvers/diff.py +106 -0
  204. package/.agent-src/templates/scripts/work_engine/resolvers/file.py +113 -0
  205. package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +90 -0
  206. package/.agent-src/templates/scripts/work_engine/scoring/__init__.py +14 -0
  207. package/.agent-src/templates/scripts/work_engine/scoring/confidence.py +300 -0
  208. package/.agent-src/templates/scripts/work_engine/stack/__init__.py +31 -0
  209. package/.agent-src/templates/scripts/work_engine/stack/detect.py +187 -0
  210. package/.agent-src/templates/scripts/work_engine/state.py +641 -0
  211. package/.claude-plugin/marketplace.json +105 -2
  212. package/AGENTS.md +36 -8
  213. package/CHANGELOG.md +558 -0
  214. package/README.md +146 -4
  215. package/composer.json +3 -0
  216. package/config/agent-settings.template.yml +45 -0
  217. package/config/gitignore-block.txt +4 -0
  218. package/docs/architecture.md +28 -1
  219. package/docs/development.md +1 -1
  220. package/docs/getting-started.md +3 -2
  221. package/docs/installation.md +86 -0
  222. package/docs/showcase.md +204 -0
  223. package/package.json +9 -1
  224. package/scripts/agent-config +274 -0
  225. package/scripts/audit_cloud_compatibility.py +288 -0
  226. package/scripts/build_cloud_bundle.py +458 -0
  227. package/scripts/build_linear_digest.py +263 -0
  228. package/scripts/chat_history.py +796 -7
  229. package/scripts/check_compression.py +139 -0
  230. package/scripts/check_iron_law_prominence.py +143 -0
  231. package/scripts/check_md_language.py +159 -0
  232. package/scripts/check_portability.py +36 -0
  233. package/scripts/check_reply_consistency.py +140 -0
  234. package/scripts/command_suggester/__init__.py +51 -0
  235. package/scripts/command_suggester/cooldown.py +132 -0
  236. package/scripts/command_suggester/loader.py +70 -0
  237. package/scripts/command_suggester/match.py +180 -0
  238. package/scripts/command_suggester/rank.py +120 -0
  239. package/scripts/command_suggester/render.py +86 -0
  240. package/scripts/command_suggester/sanitize.py +113 -0
  241. package/scripts/command_suggester/settings.py +125 -0
  242. package/scripts/command_suggester/types.py +78 -0
  243. package/scripts/hooks/augment-chat-history.sh +56 -0
  244. package/scripts/install-hooks.sh +67 -0
  245. package/scripts/install.py +150 -33
  246. package/scripts/lint_marketplace.py +27 -0
  247. package/scripts/memory_lookup.py +143 -7
  248. package/scripts/memory_status.py +76 -14
  249. package/scripts/migrate_command_suggestions.py +151 -0
  250. package/scripts/postinstall.sh +16 -0
  251. package/scripts/schemas/command.schema.json +41 -0
  252. package/scripts/skill_linter.py +67 -0
  253. package/scripts/sync_agent_settings.py +42 -12
  254. package/templates/consumer-settings/augment-cli-hooks.json +54 -0
  255. package/templates/consumer-settings/claude-settings.json +55 -1
  256. package/.agent-src/templates/scripts/implement_ticket/cli.py +0 -171
  257. package/.agent-src/templates/scripts/implement_ticket/dispatcher.py +0 -134
  258. package/.agent-src/templates/scripts/implement_ticket/steps/__init__.py +0 -49
  259. package/.agent-src/templates/scripts/implement_ticket/steps/refine.py +0 -140
  260. /package/.agent-src/templates/scripts/{implement_ticket → work_engine}/persona_policy.py +0 -0
@@ -772,6 +772,70 @@ def lint_rule(path: Path, text: str) -> LintResult:
772
772
  )
773
773
 
774
774
 
775
+ def _lint_command_suggestion_block(text: str) -> List[Issue]:
776
+ """Validate the suggestion frontmatter block (road-to-context-aware-command-suggestion).
777
+
778
+ Schema-shape is enforced upstream by validate_frontmatter; this function adds the
779
+ *conditional* content rules that JSON Schema (Draft-07 subset used here) cannot
780
+ express: trigger fields must be non-empty when eligible, rationale must be
781
+ non-empty when ineligible.
782
+ """
783
+ issues: List[Issue] = []
784
+ data, _offset = parse_frontmatter_for_schema(text)
785
+ if data is None:
786
+ return issues
787
+ suggestion = data.get("suggestion")
788
+ if suggestion is None:
789
+ issues.append(Issue(
790
+ "warning", "missing_suggestion_block",
791
+ "Command frontmatter is missing the 'suggestion' block — required by "
792
+ "road-to-context-aware-command-suggestion Phase 2.",
793
+ ))
794
+ return issues
795
+ if not isinstance(suggestion, dict):
796
+ issues.append(Issue("error", "invalid_suggestion_block", "'suggestion' must be a mapping"))
797
+ return issues
798
+ eligible = suggestion.get("eligible")
799
+ if eligible is True:
800
+ td = (suggestion.get("trigger_description") or "").strip()
801
+ tc = (suggestion.get("trigger_context") or "").strip()
802
+ if not td:
803
+ issues.append(Issue(
804
+ "error", "missing_trigger_description",
805
+ "suggestion.eligible=true requires a non-empty 'trigger_description'.",
806
+ ))
807
+ elif len(td) < 10:
808
+ issues.append(Issue(
809
+ "warning", "trigger_description_too_short",
810
+ "suggestion.trigger_description is suspiciously short (<10 chars); "
811
+ "linter rejects empty or overly generic patterns.",
812
+ ))
813
+ if not tc:
814
+ issues.append(Issue(
815
+ "error", "missing_trigger_context",
816
+ "suggestion.eligible=true requires a non-empty 'trigger_context'.",
817
+ ))
818
+ elif len(tc) < 10:
819
+ issues.append(Issue(
820
+ "warning", "trigger_context_too_short",
821
+ "suggestion.trigger_context is suspiciously short (<10 chars); "
822
+ "linter rejects empty or overly generic patterns.",
823
+ ))
824
+ elif eligible is False:
825
+ rationale = (suggestion.get("rationale") or "").strip()
826
+ if not rationale:
827
+ issues.append(Issue(
828
+ "error", "missing_suggestion_rationale",
829
+ "suggestion.eligible=false requires a non-empty 'rationale'.",
830
+ ))
831
+ else:
832
+ issues.append(Issue(
833
+ "error", "invalid_suggestion_eligible",
834
+ "suggestion.eligible must be true or false.",
835
+ ))
836
+ return issues
837
+
838
+
775
839
  def lint_command(path: Path, text: str) -> LintResult:
776
840
  issues: List[Issue] = []
777
841
  suggestions: List[str] = []
@@ -800,6 +864,9 @@ def lint_command(path: Path, text: str) -> LintResult:
800
864
  if not description:
801
865
  issues.append(Issue("warning", "missing_description", "Frontmatter description is missing"))
802
866
 
867
+ # suggestion block (road-to-context-aware-command-suggestion Phase 2)
868
+ issues.extend(_lint_command_suggestion_block(text))
869
+
803
870
  # --- Structure checks ---
804
871
  if not H1_PATTERN.search(text):
805
872
  issues.append(Issue("error", "missing_h1", "Command is missing an H1 heading (# Title)"))
@@ -47,29 +47,48 @@ DEFAULT_PROFILE_DIR = Path(__file__).resolve().parent.parent / "config" / "profi
47
47
 
48
48
 
49
49
  def _flatten(data: dict, prefix: str = "") -> dict[str, object]:
50
- """Flatten nested dicts to dotted keys — one level of nesting supported."""
50
+ """Flatten nested dicts to dotted keys — recurses to all leaves.
51
+
52
+ Lists, scalars, and ``None`` are leaves. Dicts are walked and their
53
+ keys folded into the dotted path.
54
+ """
51
55
  out: dict[str, object] = {}
52
56
  for key, value in data.items():
53
57
  path = f"{prefix}{key}"
54
58
  if isinstance(value, dict):
55
- for sub_key, sub_val in value.items():
56
- out[f"{path}.{sub_key}"] = sub_val
59
+ out.update(_flatten(value, prefix=f"{path}."))
57
60
  else:
58
61
  out[path] = value
59
62
  return out
60
63
 
61
64
 
62
- def _as_scalar_text(value: object) -> str:
63
- """Normalize a parsed YAML value to the raw string form expected by
64
- `install._replace_template_value` — which re-quotes via `_yaml_scalar`
65
- internally, so we must pass the *unquoted* payload here."""
65
+ def _as_yaml_value(value: object) -> str | None:
66
+ """Format *value* as an inline-YAML literal.
67
+
68
+ Returns ``None`` when the value cannot be safely represented as a
69
+ scalar / flow-style sequence (e.g. unsupported types). Callers
70
+ must skip those keys so the template default sticks instead of
71
+ producing malformed YAML.
72
+ """
66
73
  if isinstance(value, bool):
67
74
  return "true" if value else "false"
68
75
  if isinstance(value, int):
69
76
  return str(value)
77
+ if isinstance(value, float):
78
+ return repr(value)
70
79
  if value is None:
71
- return ""
72
- return str(value)
80
+ return "~"
81
+ if isinstance(value, list):
82
+ items: list[str] = []
83
+ for item in value:
84
+ rendered = _as_yaml_value(item)
85
+ if rendered is None:
86
+ return None
87
+ items.append(rendered)
88
+ return "[" + ", ".join(items) + "]"
89
+ if isinstance(value, str):
90
+ return _install._yaml_scalar(value)
91
+ return None
73
92
 
74
93
 
75
94
  def _template_keys(template_body: str) -> set[str]:
@@ -81,10 +100,18 @@ def _template_keys(template_body: str) -> set[str]:
81
100
 
82
101
 
83
102
  def _apply_user_values(template_body: str, user_flat: dict[str, object]) -> str:
84
- """Overlay every known user value on the rendered template body."""
103
+ """Overlay every known user value on the rendered template body.
104
+
105
+ Keys whose value cannot be rendered inline (see :func:`_as_yaml_value`)
106
+ are skipped so the template default survives instead of corrupting
107
+ the file.
108
+ """
85
109
  body = template_body
86
110
  for dotted, value in user_flat.items():
87
- body = _install._replace_template_value(body, dotted, _as_scalar_text(value))
111
+ rendered = _as_yaml_value(value)
112
+ if rendered is None:
113
+ continue
114
+ body = _install._replace_template_value_raw(body, dotted, rendered)
88
115
  return body
89
116
 
90
117
 
@@ -100,7 +127,10 @@ def _append_unknown(body: str, user_flat: dict[str, object], known: set[str]) ->
100
127
  "_user:",
101
128
  ]
102
129
  for key in unknown:
103
- lines.append(f" {key}: {_install._yaml_scalar(_as_scalar_text(user_flat[key]))}")
130
+ rendered = _as_yaml_value(user_flat[key])
131
+ if rendered is None:
132
+ continue
133
+ lines.append(f" {key}: {rendered}")
104
134
  suffix = "\n".join(lines) + "\n"
105
135
  return body + (suffix if body.endswith("\n") else "\n" + suffix)
106
136
 
@@ -0,0 +1,54 @@
1
+ {
2
+ "// Instructions": "OPTIONAL: merge this into ~/.augment/settings.json (user-scope, NOT project-scope) to wire chat-history hooks for the Augment CLI.",
3
+ "// Why user-scope": "The Augment CLI reads hooks from ~/.augment/settings.json (per https://docs.augmentcode.com/cli/hooks.md). Project-scoped .augment/settings.json belongs to the IDE plugin, which has no documented hook surface as of 2026-04-30.",
4
+ "// IDE plugin": "Use the /chat-history-checkpoint command at phase boundaries instead — see rules/chat-history.md.",
5
+ "// Wrapper": "The command assumes the project-root ./agent-config wrapper is on PATH or invoked with a project-relative cwd. Adjust to absolute paths if your shell does not chdir into the project.",
6
+
7
+ "hooks": {
8
+ "SessionStart": [
9
+ {
10
+ "hooks": [
11
+ {
12
+ "type": "command",
13
+ "command": "./agent-config chat-history:hook --platform augment",
14
+ "timeout": 5000
15
+ }
16
+ ]
17
+ }
18
+ ],
19
+ "PostToolUse": [
20
+ {
21
+ "matcher": ".*",
22
+ "hooks": [
23
+ {
24
+ "type": "command",
25
+ "command": "./agent-config chat-history:hook --platform augment",
26
+ "timeout": 3000
27
+ }
28
+ ]
29
+ }
30
+ ],
31
+ "Stop": [
32
+ {
33
+ "hooks": [
34
+ {
35
+ "type": "command",
36
+ "command": "./agent-config chat-history:hook --platform augment",
37
+ "timeout": 3000
38
+ }
39
+ ]
40
+ }
41
+ ],
42
+ "SessionEnd": [
43
+ {
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "./agent-config chat-history:hook --platform augment",
48
+ "timeout": 3000
49
+ }
50
+ ]
51
+ }
52
+ ]
53
+ }
54
+ }
@@ -1,9 +1,63 @@
1
1
  {
2
- "// Instructions": "Copy this into your project's .claude/settings.json to auto-enable the agent-config plugin.",
2
+ "// Instructions": "Copy this into your project's .claude/settings.json to auto-enable the agent-config plugin and chat-history hooks.",
3
3
  "// After setup": "Claude Code will load the plugin when the marketplace is installed.",
4
4
  "// Install marketplace": "Run: claude plugin marketplace add event4u-app/agent-config",
5
+ "// Hooks": "Hooks call ./agent-config (the wrapper installed at the project root) which dispatches to scripts/chat_history.py hook-dispatch. They are no-ops when chat_history.enabled is false in .agent-settings.yml.",
5
6
 
6
7
  "enabledPlugins": {
7
8
  "agent-conf@event4u": true
9
+ },
10
+
11
+ "hooks": {
12
+ "SessionStart": [
13
+ {
14
+ "hooks": [
15
+ {
16
+ "type": "command",
17
+ "command": "./agent-config chat-history:hook --platform claude"
18
+ }
19
+ ]
20
+ }
21
+ ],
22
+ "UserPromptSubmit": [
23
+ {
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "./agent-config chat-history:hook --platform claude"
28
+ }
29
+ ]
30
+ }
31
+ ],
32
+ "PostToolUse": [
33
+ {
34
+ "hooks": [
35
+ {
36
+ "type": "command",
37
+ "command": "./agent-config chat-history:hook --platform claude"
38
+ }
39
+ ]
40
+ }
41
+ ],
42
+ "Stop": [
43
+ {
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "./agent-config chat-history:hook --platform claude"
48
+ }
49
+ ]
50
+ }
51
+ ],
52
+ "SessionEnd": [
53
+ {
54
+ "hooks": [
55
+ {
56
+ "type": "command",
57
+ "command": "./agent-config chat-history:hook --platform claude"
58
+ }
59
+ ]
60
+ }
61
+ ]
8
62
  }
9
63
  }
@@ -1,171 +0,0 @@
1
- """Command-line entry point for ``/implement-ticket``.
2
-
3
- Minimal Option-A transport: the script loads a persisted
4
- ``DeliveryState`` (or builds one from a ticket file), runs the
5
- dispatcher once, writes the updated state back, and prints either
6
- the delivery report (on SUCCESS) or the halt surface — directive
7
- plus numbered questions — on BLOCKED/PARTIAL.
8
-
9
- The script never edits code, runs tests, or opens pull requests.
10
- All of that is delegated to the agent via ``@agent-directive:``
11
- markers per
12
- ``agents/contexts/implement-ticket-flow.md#agent-directives``. The
13
- agent executes the directive, writes the resulting slice back to
14
- the state file, and re-invokes this script to resume.
15
-
16
- Exit codes:
17
-
18
- - ``0`` — flow reached SUCCESS; ``state.report`` printed.
19
- - ``1`` — flow halted BLOCKED; halt surface printed on stdout, the
20
- state file carries the updated ``outcomes`` and ``questions`` so
21
- the agent can resume.
22
- - ``2`` — argument or I/O error (ticket file missing, JSON parse
23
- failure, etc.). The state file is *not* written in this case.
24
- """
25
- from __future__ import annotations
26
-
27
- import argparse
28
- import json
29
- import sys
30
- from dataclasses import asdict
31
- from pathlib import Path
32
- from typing import Sequence
33
-
34
- from .delivery_state import DeliveryState, Outcome
35
- from .dispatcher import dispatch
36
- from .steps import analyze, implement, memory, plan, refine, report, verify
37
- from .steps import test as test_step
38
-
39
- DEFAULT_STATE_FILE = Path(".implement-ticket-state.json")
40
- """State file used when ``--state-file`` is not passed."""
41
-
42
- _STEPS = {
43
- "refine": refine.run,
44
- "memory": memory.run,
45
- "analyze": analyze.run,
46
- "plan": plan.run,
47
- "implement": implement.run,
48
- "test": test_step.run,
49
- "verify": verify.run,
50
- "report": report.run,
51
- }
52
-
53
-
54
- def main(argv: Sequence[str] | None = None) -> int:
55
- """Run one dispatch cycle against the persisted state.
56
-
57
- ``argv`` is taken as-is; pass ``None`` to fall back to
58
- ``sys.argv[1:]`` (the usual entry-point contract).
59
- """
60
- parser = _build_parser()
61
- args = parser.parse_args(argv)
62
- state_file: Path = args.state_file
63
-
64
- try:
65
- state = _load_or_build(state_file, args)
66
- except _CLIError as exc:
67
- print(f"error: {exc}", file=sys.stderr)
68
- return 2
69
-
70
- final, halting = dispatch(state, _STEPS)
71
- _save(state_file, state)
72
- _emit(state, final, halting)
73
- return 0 if final is Outcome.SUCCESS else 1
74
-
75
-
76
- def _build_parser() -> argparse.ArgumentParser:
77
- parser = argparse.ArgumentParser(
78
- prog="implement-ticket",
79
- description="Run one dispatch cycle of the /implement-ticket flow.",
80
- )
81
- parser.add_argument(
82
- "--state-file",
83
- type=Path,
84
- default=DEFAULT_STATE_FILE,
85
- help=f"Path to persisted state JSON (default: {DEFAULT_STATE_FILE}).",
86
- )
87
- parser.add_argument(
88
- "--ticket-file",
89
- type=Path,
90
- default=None,
91
- help="JSON file carrying the ticket payload; used only when the "
92
- "state file does not exist yet.",
93
- )
94
- parser.add_argument(
95
- "--persona",
96
- type=str,
97
- default=None,
98
- help="Persona name (senior-engineer | qa | advisory). Only honoured "
99
- "when the state file does not exist yet; ignored on resume so a "
100
- "mid-flight persona switch cannot silently change behaviour.",
101
- )
102
- return parser
103
-
104
-
105
- def _load_or_build(state_file: Path, args: argparse.Namespace) -> DeliveryState:
106
- """Return the state to dispatch against — either loaded or freshly built."""
107
- if state_file.exists():
108
- return _load(state_file)
109
- if args.ticket_file is None:
110
- raise _CLIError(
111
- f"No state file at {state_file} and no --ticket-file given; "
112
- "cannot build an initial DeliveryState.",
113
- )
114
- ticket = _read_json(args.ticket_file)
115
- if not isinstance(ticket, dict):
116
- raise _CLIError(
117
- f"--ticket-file must carry a JSON object; got {type(ticket).__name__}.",
118
- )
119
- kwargs: dict = {"ticket": ticket}
120
- if args.persona:
121
- kwargs["persona"] = args.persona
122
- return DeliveryState(**kwargs)
123
-
124
-
125
- def _load(state_file: Path) -> DeliveryState:
126
- data = _read_json(state_file)
127
- if not isinstance(data, dict):
128
- raise _CLIError(
129
- f"State file {state_file} must carry a JSON object; "
130
- f"got {type(data).__name__}.",
131
- )
132
- try:
133
- return DeliveryState(**data)
134
- except TypeError as exc:
135
- raise _CLIError(f"State file shape is invalid: {exc}") from exc
136
-
137
-
138
- def _save(state_file: Path, state: DeliveryState) -> None:
139
- """Persist ``state`` as pretty JSON for diffing + human inspection."""
140
- state_file.parent.mkdir(parents=True, exist_ok=True)
141
- state_file.write_text(
142
- json.dumps(asdict(state), indent=2, ensure_ascii=False) + "\n",
143
- encoding="utf-8",
144
- )
145
-
146
-
147
- def _read_json(path: Path):
148
- try:
149
- raw = path.read_text(encoding="utf-8")
150
- except OSError as exc:
151
- raise _CLIError(f"Cannot read {path}: {exc}") from exc
152
- try:
153
- return json.loads(raw)
154
- except json.JSONDecodeError as exc:
155
- raise _CLIError(f"Invalid JSON in {path}: {exc}") from exc
156
-
157
-
158
- def _emit(state: DeliveryState, final: Outcome, halting: str | None) -> None:
159
- if final is Outcome.SUCCESS:
160
- print(state.report)
161
- return
162
- print(f"[halt] outcome={final.value} step={halting or '(none)'}")
163
- for line in state.questions:
164
- print(line)
165
-
166
-
167
- class _CLIError(Exception):
168
- """Raised on configuration or I/O problems. Converted to exit code 2."""
169
-
170
-
171
- __all__ = ["DEFAULT_STATE_FILE", "main"]
@@ -1,134 +0,0 @@
1
- """Linear step dispatcher for ``/implement-ticket``.
2
-
3
- The dispatcher holds no business logic. It walks the fixed eight-step
4
- order declared in ``agents/contexts/implement-ticket-flow.md``, hands
5
- each step a live ``DeliveryState``, and honours the three terminal
6
- outcomes:
7
-
8
- - ``SUCCESS`` — record and advance.
9
- - ``BLOCKED`` — record, copy questions onto the state, halt.
10
- - ``PARTIAL`` — record, copy questions onto the state, halt.
11
-
12
- Resumption semantics (Option A, flow contract §agent-directives):
13
- steps whose name is already marked ``success`` in
14
- ``state.outcomes`` are **skipped**. This lets a caller re-invoke the
15
- dispatcher after executing an agent-directive (the ``implement``,
16
- ``test``, ``verify`` steps cannot run from pure Python), update the
17
- relevant slice of ``DeliveryState``, record ``success`` on the
18
- resumed step, and continue without replaying earlier work.
19
-
20
- Step handlers are injected by the caller rather than discovered at
21
- import time. Phase 1 shipped the dispatcher with mock handlers;
22
- Phase 2 wires the real ones under ``steps/``. Keeping injection
23
- explicit means the dispatcher is trivially testable and never
24
- depends on handler import order.
25
- """
26
- from __future__ import annotations
27
-
28
- from collections.abc import Mapping
29
-
30
- from .delivery_state import DeliveryState, Outcome, Step, StepResult
31
-
32
- STEP_ORDER: tuple[str, ...] = (
33
- "refine",
34
- "memory",
35
- "analyze",
36
- "plan",
37
- "implement",
38
- "test",
39
- "verify",
40
- "report",
41
- )
42
- """Canonical execution order. Eight steps, fixed, no branching.
43
-
44
- Changing this order is a roadmap-level decision — not a PR rider — per
45
- the surface-growth guardrails in
46
- ``agents/roadmaps/road-to-implement-ticket.md``.
47
- """
48
-
49
-
50
- def dispatch(
51
- state: DeliveryState,
52
- steps: Mapping[str, Step],
53
- ) -> tuple[Outcome, str | None]:
54
- """Run the eight steps linearly against ``state``.
55
-
56
- Returns a ``(final_outcome, halting_step)`` tuple. ``halting_step``
57
- is ``None`` when every step succeeded; otherwise it carries the
58
- name of the step whose result halted the flow.
59
-
60
- Parameters
61
- ----------
62
- state:
63
- Live ``DeliveryState``. Mutated in place: each step's outcome
64
- is recorded in ``state.outcomes`` under the step name, and
65
- any surfaced questions land on ``state.questions``.
66
- steps:
67
- Mapping from step name to handler. Every entry in
68
- :data:`STEP_ORDER` must be present; missing entries raise
69
- ``KeyError`` at dispatch time rather than silently skipping,
70
- so incomplete wiring surfaces as a hard failure.
71
-
72
- Raises
73
- ------
74
- KeyError
75
- If ``steps`` does not cover every entry in
76
- :data:`STEP_ORDER`.
77
- """
78
- _assert_all_steps_present(steps)
79
-
80
- # Clear stale questions from a previous halt before we resume so
81
- # the caller never mistakes old options for fresh ones.
82
- state.questions = []
83
-
84
- for name in STEP_ORDER:
85
- if state.outcomes.get(name) == Outcome.SUCCESS.value:
86
- # Already completed on an earlier invocation — skip per the
87
- # resume contract. The caller is responsible for keeping
88
- # ``state.outcomes`` and the matching slice in sync.
89
- continue
90
-
91
- handler = steps[name]
92
- result = handler(state)
93
- _validate_step_result(name, result)
94
-
95
- state.outcomes[name] = result.outcome.value
96
-
97
- if result.outcome is Outcome.BLOCKED:
98
- state.questions = list(result.questions)
99
- return Outcome.BLOCKED, name
100
-
101
- if result.outcome is Outcome.PARTIAL:
102
- state.questions = list(result.questions)
103
- return Outcome.PARTIAL, name
104
-
105
- return Outcome.SUCCESS, None
106
-
107
-
108
- def _assert_all_steps_present(steps: Mapping[str, Step]) -> None:
109
- """Reject an incomplete step mapping up front.
110
-
111
- We deliberately fail loudly here: a missing step would otherwise
112
- raise deep inside the dispatch loop after partial state mutation,
113
- which makes debugging the wiring harder than it needs to be.
114
- """
115
- missing = [name for name in STEP_ORDER if name not in steps]
116
- if missing:
117
- raise KeyError(
118
- "Step mapping is missing handlers for: " + ", ".join(missing),
119
- )
120
-
121
-
122
- def _validate_step_result(name: str, result: StepResult) -> None:
123
- """Enforce the blocked/partial invariant: questions must be set.
124
-
125
- A step that blocks without surfacing a question is a bug — there
126
- is nothing for the user to answer. We raise ``ValueError`` instead
127
- of silently recording the outcome so the defect is visible at the
128
- earliest possible point.
129
- """
130
- if result.outcome in (Outcome.BLOCKED, Outcome.PARTIAL) and not result.questions:
131
- raise ValueError(
132
- f"Step {name!r} returned {result.outcome.value} with no questions; "
133
- "blocked and partial outcomes must surface at least one numbered option.",
134
- )
@@ -1,49 +0,0 @@
1
- """Step handlers for the ``/implement-ticket`` dispatcher.
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
- Phase 2 ships all eight step handlers. The deterministic gates
11
- (``refine``, ``memory``, ``analyze``) validate upstream state; the
12
- delegation gates (``plan``, ``implement``, ``test``, ``verify``)
13
- halt with ``@agent-directive:`` markers so the orchestrator can
14
- invoke the matching skill and resume. ``report`` renders the
15
- delivery Markdown once everything else has succeeded. See
16
- ``agents/roadmaps/road-to-implement-ticket.md`` for the shipping
17
- order and ``agents/contexts/implement-ticket-flow.md`` for the
18
- slice contracts each handler writes to.
19
- """
20
- from __future__ import annotations
21
-
22
- from . import analyze, implement, memory, plan, refine, report, test, verify
23
-
24
- _STEPS = (refine, memory, analyze, plan, implement, test, verify, report)
25
-
26
-
27
- def all_ambiguities() -> dict[str, tuple[dict[str, str], ...]]:
28
- """Return `{step_name: AMBIGUITIES}` for every step in flow order.
29
-
30
- Used by documentation generators and the ``test_ambiguity_coverage``
31
- suite to prove every step explicitly declares what can surface a
32
- ``BLOCKED`` outcome. Steps that always succeed (``memory``,
33
- ``report``) return an empty tuple — declared intent, not an
34
- omission.
35
- """
36
- return {step.__name__.rsplit(".", 1)[-1]: step.AMBIGUITIES for step in _STEPS}
37
-
38
-
39
- __all__ = [
40
- "all_ambiguities",
41
- "analyze",
42
- "implement",
43
- "memory",
44
- "plan",
45
- "refine",
46
- "report",
47
- "test",
48
- "verify",
49
- ]