@event4u/agent-config 1.18.0 → 1.19.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 (126) hide show
  1. package/.agent-src/commands/council/default.md +74 -76
  2. package/.agent-src/commands/feature/roadmap.md +22 -0
  3. package/.agent-src/commands/roadmap/create.md +38 -6
  4. package/.agent-src/commands/roadmap/execute.md +36 -9
  5. package/.agent-src/rules/agent-authority.md +1 -0
  6. package/.agent-src/rules/agent-docs.md +1 -0
  7. package/.agent-src/rules/analysis-skill-routing.md +1 -0
  8. package/.agent-src/rules/architecture.md +1 -0
  9. package/.agent-src/rules/artifact-drafting-protocol.md +1 -0
  10. package/.agent-src/rules/artifact-engagement-recording.md +1 -0
  11. package/.agent-src/rules/ask-when-uncertain.md +1 -0
  12. package/.agent-src/rules/augment-portability.md +1 -0
  13. package/.agent-src/rules/augment-source-of-truth.md +1 -0
  14. package/.agent-src/rules/autonomous-execution.md +1 -0
  15. package/.agent-src/rules/capture-learnings.md +1 -0
  16. package/.agent-src/rules/chat-history-cadence.md +34 -0
  17. package/.agent-src/rules/chat-history-ownership.md +1 -0
  18. package/.agent-src/rules/chat-history-visibility.md +1 -0
  19. package/.agent-src/rules/cli-output-handling.md +2 -2
  20. package/.agent-src/rules/command-suggestion-policy.md +1 -0
  21. package/.agent-src/rules/commit-conventions.md +1 -0
  22. package/.agent-src/rules/commit-policy.md +1 -0
  23. package/.agent-src/rules/context-hygiene.md +22 -0
  24. package/.agent-src/rules/direct-answers.md +1 -0
  25. package/.agent-src/rules/docker-commands.md +1 -0
  26. package/.agent-src/rules/docs-sync.md +1 -0
  27. package/.agent-src/rules/downstream-changes.md +1 -0
  28. package/.agent-src/rules/e2e-testing.md +1 -0
  29. package/.agent-src/rules/guidelines.md +1 -0
  30. package/.agent-src/rules/improve-before-implement.md +1 -0
  31. package/.agent-src/rules/language-and-tone.md +1 -0
  32. package/.agent-src/rules/laravel-translations.md +1 -0
  33. package/.agent-src/rules/markdown-safe-codeblocks.md +1 -0
  34. package/.agent-src/rules/minimal-safe-diff.md +1 -0
  35. package/.agent-src/rules/missing-tool-handling.md +1 -0
  36. package/.agent-src/rules/model-recommendation.md +1 -0
  37. package/.agent-src/rules/no-cheap-questions.md +1 -0
  38. package/.agent-src/rules/no-roadmap-references.md +1 -0
  39. package/.agent-src/rules/non-destructive-by-default.md +1 -0
  40. package/.agent-src/rules/onboarding-gate.md +26 -0
  41. package/.agent-src/rules/package-ci-checks.md +1 -0
  42. package/.agent-src/rules/php-coding.md +1 -0
  43. package/.agent-src/rules/preservation-guard.md +1 -0
  44. package/.agent-src/rules/review-routing-awareness.md +1 -0
  45. package/.agent-src/rules/reviewer-awareness.md +1 -0
  46. package/.agent-src/rules/roadmap-progress-sync.md +22 -0
  47. package/.agent-src/rules/role-mode-adherence.md +2 -2
  48. package/.agent-src/rules/rule-type-governance.md +1 -0
  49. package/.agent-src/rules/runtime-safety.md +1 -0
  50. package/.agent-src/rules/scope-control.md +1 -0
  51. package/.agent-src/rules/security-sensitive-stop.md +1 -0
  52. package/.agent-src/rules/size-enforcement.md +1 -0
  53. package/.agent-src/rules/skill-improvement-trigger.md +1 -0
  54. package/.agent-src/rules/skill-quality.md +1 -0
  55. package/.agent-src/rules/slash-command-routing-policy.md +39 -0
  56. package/.agent-src/rules/think-before-action.md +1 -0
  57. package/.agent-src/rules/token-efficiency.md +1 -0
  58. package/.agent-src/rules/tool-safety.md +1 -0
  59. package/.agent-src/rules/ui-audit-gate.md +1 -0
  60. package/.agent-src/rules/upstream-proposal.md +1 -0
  61. package/.agent-src/rules/user-interaction.md +1 -0
  62. package/.agent-src/rules/verify-before-complete.md +1 -0
  63. package/.agent-src/skills/roadmap-management/SKILL.md +29 -4
  64. package/.agent-src/skills/verify-completion-evidence/SKILL.md +8 -1
  65. package/.agent-src/templates/agent-settings.md +16 -0
  66. package/.agent-src/templates/roadmaps.md +8 -3
  67. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +9 -0
  68. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +4 -0
  69. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +4 -0
  70. package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.py +163 -0
  71. package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +111 -0
  72. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +36 -0
  73. package/.agent-src/templates/scripts/work_engine/scoring/decision_trace.py +141 -0
  74. package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +125 -0
  75. package/.claude-plugin/marketplace.json +1 -1
  76. package/CHANGELOG.md +62 -0
  77. package/README.md +19 -19
  78. package/config/agent-settings.template.yml +23 -0
  79. package/docs/catalog.md +5 -2
  80. package/docs/contracts/adr-settings-sync-engine.md +127 -0
  81. package/docs/contracts/decision-trace-v1.md +146 -0
  82. package/docs/contracts/file-ownership-matrix.json +7 -0
  83. package/docs/contracts/hook-architecture-v1.md +213 -0
  84. package/docs/contracts/memory-visibility-v1.md +138 -0
  85. package/docs/contracts/one-off-script-lifecycle.md +109 -0
  86. package/docs/contracts/rule-interactions.yml +22 -0
  87. package/docs/customization.md +1 -0
  88. package/docs/development.md +4 -1
  89. package/docs/guidelines/agent-infra/layered-settings.md +32 -13
  90. package/package.json +1 -1
  91. package/scripts/agent-config +44 -0
  92. package/scripts/ai_council/bundler.py +3 -3
  93. package/scripts/ai_council/clients.py +24 -8
  94. package/scripts/ai_council/one_off_archive/2026-05/README.md +22 -0
  95. package/scripts/ai_council/one_off_archive/2026-05/_one_off_roundtrip.py +13 -8
  96. package/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +180 -0
  97. package/scripts/ai_council/session.py +92 -0
  98. package/scripts/capture_showcase_session.py +361 -0
  99. package/scripts/chat_history.py +11 -1
  100. package/scripts/check_always_budget.py +7 -2
  101. package/scripts/context_hygiene_hook.py +14 -6
  102. package/scripts/council_cli.py +357 -0
  103. package/scripts/hook_manifest.yaml +184 -0
  104. package/scripts/hooks/__init__.py +1 -0
  105. package/scripts/hooks/augment-dispatcher.sh +72 -0
  106. package/scripts/hooks/cline-dispatcher.sh +86 -0
  107. package/scripts/hooks/cursor-dispatcher.sh +76 -0
  108. package/scripts/hooks/dispatch_hook.py +348 -0
  109. package/scripts/hooks/envelope.py +98 -0
  110. package/scripts/hooks/gemini-dispatcher.sh +117 -0
  111. package/scripts/hooks/state_io.py +122 -0
  112. package/scripts/hooks/windsurf-dispatcher.sh +123 -0
  113. package/scripts/hooks_status.py +146 -0
  114. package/scripts/install.py +725 -87
  115. package/scripts/install.sh +1 -1
  116. package/scripts/lint_hook_manifest.py +216 -0
  117. package/scripts/lint_one_off_age.py +184 -0
  118. package/scripts/lint_rule_tiers.py +78 -0
  119. package/scripts/lint_showcase_sessions.py +148 -0
  120. package/scripts/minimal_safe_diff_hook.py +245 -0
  121. package/scripts/onboarding_gate_hook.py +13 -8
  122. package/scripts/readme_linter.py +12 -3
  123. package/scripts/roadmap_progress_hook.py +5 -0
  124. package/scripts/sync_agent_settings.py +32 -129
  125. package/scripts/sync_yaml_rt.py +734 -0
  126. package/scripts/verify_before_complete_hook.py +216 -0
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env python3
2
+ """Platform-agnostic hook for the `verify-before-complete` rule.
3
+
4
+ Records observable evidence that a verification command (tests, quality
5
+ tools, build) ran. The rule body cites the resulting state file as the
6
+ source of truth for the "have I verified this turn?" question. The hook
7
+ itself never blocks — it is observability infra, not control flow.
8
+
9
+ Wired to multiple events via the manifest:
10
+ - session_start / user_prompt_submit → reset turn-scoped counters
11
+ - post_tool_use → inspect tool + command, record verifications
12
+ - stop → record stop fired (claim-done window)
13
+
14
+ Output: `agents/state/verify-before-complete.json`
15
+ {
16
+ "schema_version": 1,
17
+ "session_id": "<str>",
18
+ "turn_started_at": "<iso8601|null>",
19
+ "last_verification": {"command": ..., "tool": ..., "at": ...} | null,
20
+ "verifications_this_turn": <int>,
21
+ "verifications_this_session": <int>,
22
+ "last_stop_at": "<iso8601|null>",
23
+ "verified_this_turn": <bool>,
24
+ "checked_at": "<iso8601>"
25
+ }
26
+
27
+ Exit code is always 0.
28
+ """
29
+ from __future__ import annotations
30
+
31
+ import argparse
32
+ import datetime as _dt
33
+ import json
34
+ import re
35
+ import sys
36
+ from pathlib import Path
37
+
38
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
39
+ from hooks.state_io import atomic_write_json # noqa: E402
40
+
41
+ STATE_FILE = Path("agents") / "state" / "verify-before-complete.json"
42
+
43
+ # Tool names across platforms whose `command` / `tool_input.command` field
44
+ # carries a shell command we can inspect. Edit tools are deliberately
45
+ # excluded — they cannot run verification.
46
+ COMMAND_TOOLS = frozenset({
47
+ "launch-process", "launch_process", # Augment
48
+ "Bash", "BashTool", # Claude Code
49
+ "run-process", "runProcess", # variants
50
+ "shell", "execute_shell", # generic / Cline
51
+ "RunShellCommand", # Cursor
52
+ })
53
+
54
+ # Permissive verification-command pattern. Observability — false positives
55
+ # are cheaper than false negatives. Word-boundary anchored on common
56
+ # shell separators so chained commands (`task sync && task ci`) match.
57
+ _VERIFICATION_RE = re.compile(
58
+ r'(?:^|[\s;&|`(])('
59
+ r'task\s+(?:ci|test|tests|lint|check|qa|phpstan|rector|ecs|pest|pytest)'
60
+ r'|(?:\./|\.venv/bin/|vendor/bin/)?(?:pest|phpunit|phpstan|psalm|rector|ecs)\b'
61
+ r'|(?:python3?|\.venv/bin/python3?)\s+-m\s+pytest'
62
+ r'|pytest\b'
63
+ r'|(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|check|lint|typecheck|tsc)'
64
+ r'|cargo\s+(?:test|check|clippy)'
65
+ r'|go\s+test'
66
+ r'|make\s+(?:test|check|lint)'
67
+ r'|composer\s+(?:test|check|lint|phpstan)'
68
+ r'|(?:php\s+)?artisan\s+test'
69
+ r')',
70
+ re.IGNORECASE,
71
+ )
72
+
73
+
74
+ def _now() -> str:
75
+ return _dt.datetime.now(_dt.timezone.utc).isoformat(timespec="seconds")
76
+
77
+
78
+ def _empty_state() -> dict:
79
+ return {
80
+ "schema_version": 1,
81
+ "session_id": "",
82
+ "turn_started_at": None,
83
+ "last_verification": None,
84
+ "verifications_this_turn": 0,
85
+ "verifications_this_session": 0,
86
+ "last_stop_at": None,
87
+ "verified_this_turn": False,
88
+ "checked_at": _now(),
89
+ }
90
+
91
+
92
+ def _load_state(target: Path) -> dict:
93
+ if not target.is_file():
94
+ return _empty_state()
95
+ try:
96
+ decoded = json.loads(target.read_text(encoding="utf-8"))
97
+ if isinstance(decoded, dict):
98
+ return {**_empty_state(), **decoded}
99
+ except (OSError, json.JSONDecodeError):
100
+ pass
101
+ return _empty_state()
102
+
103
+
104
+ def _extract_command(payload: dict) -> tuple[str | None, str | None]:
105
+ """Return (tool_name, command_text) from a tool-event payload."""
106
+ tool = (payload.get("tool_name") or payload.get("toolName")
107
+ or payload.get("tool"))
108
+ if not isinstance(tool, str) or tool not in COMMAND_TOOLS:
109
+ return (tool if isinstance(tool, str) else None, None)
110
+ ti = payload.get("tool_input")
111
+ if isinstance(ti, dict):
112
+ for key in ("command", "cmd", "shell_command"):
113
+ v = ti.get(key)
114
+ if isinstance(v, str) and v:
115
+ return (tool, v)
116
+ # Some platforms surface the command at the top level.
117
+ for key in ("command", "cmd"):
118
+ v = payload.get(key)
119
+ if isinstance(v, str) and v:
120
+ return (tool, v)
121
+ return (tool, None)
122
+
123
+
124
+ def _is_verification(command: str) -> bool:
125
+ return bool(_VERIFICATION_RE.search(command))
126
+
127
+
128
+ def _reset_turn(state: dict, session_id: str) -> dict:
129
+ state["session_id"] = session_id or state.get("session_id") or ""
130
+ state["turn_started_at"] = _now()
131
+ state["verifications_this_turn"] = 0
132
+ state["verified_this_turn"] = False
133
+ return state
134
+
135
+
136
+ def _update(state: dict, event: str, envelope: dict) -> dict:
137
+ session_id = envelope.get("session_id") or state.get("session_id") or ""
138
+ if session_id and session_id != state.get("session_id"):
139
+ # Session boundary — reset session-scoped counters.
140
+ state["session_id"] = session_id
141
+ state["verifications_this_session"] = 0
142
+ state = _reset_turn(state, session_id)
143
+
144
+ payload = envelope.get("payload") or {}
145
+ if not isinstance(payload, dict):
146
+ payload = {}
147
+
148
+ if event in ("session_start", "user_prompt_submit"):
149
+ state = _reset_turn(state, session_id)
150
+ elif event == "post_tool_use":
151
+ tool, cmd = _extract_command(payload)
152
+ if cmd and _is_verification(cmd):
153
+ state["last_verification"] = {
154
+ "command": cmd[:512],
155
+ "tool": tool,
156
+ "at": _now(),
157
+ "platform": envelope.get("platform") or "",
158
+ }
159
+ state["verifications_this_turn"] = int(
160
+ state.get("verifications_this_turn") or 0) + 1
161
+ state["verifications_this_session"] = int(
162
+ state.get("verifications_this_session") or 0) + 1
163
+ state["verified_this_turn"] = True
164
+ elif event == "stop":
165
+ state["last_stop_at"] = _now()
166
+
167
+ state["checked_at"] = _now()
168
+ return state
169
+
170
+
171
+ def run(stdin_text: str, *, consumer_root: Path, verbose: bool = False) -> int:
172
+ envelope: dict = {}
173
+ if stdin_text.strip():
174
+ try:
175
+ decoded = json.loads(stdin_text)
176
+ if isinstance(decoded, dict):
177
+ envelope = decoded
178
+ except json.JSONDecodeError:
179
+ envelope = {}
180
+
181
+ event = envelope.get("event") or ""
182
+ target = consumer_root / STATE_FILE
183
+ state = _load_state(target)
184
+ state = _update(state, event, envelope)
185
+
186
+ try:
187
+ atomic_write_json(target, state)
188
+ except OSError:
189
+ if verbose:
190
+ print("verify-before-complete-hook: state write failed",
191
+ file=sys.stderr)
192
+ return 0
193
+
194
+ if verbose:
195
+ print(
196
+ f"verify-before-complete-hook: event={event} "
197
+ f"verified_this_turn={state.get('verified_this_turn')} "
198
+ f"verifications_this_turn={state.get('verifications_this_turn')}",
199
+ file=sys.stderr,
200
+ )
201
+ return 0
202
+
203
+
204
+ def main(argv: list[str] | None = None) -> int:
205
+ parser = argparse.ArgumentParser(description=__doc__)
206
+ parser.add_argument("--platform", default="generic",
207
+ help="informational platform tag")
208
+ parser.add_argument("--verbose", action="store_true",
209
+ help="emit one stderr line per invocation")
210
+ args = parser.parse_args(argv)
211
+ return run(sys.stdin.read(), consumer_root=Path.cwd(),
212
+ verbose=args.verbose)
213
+
214
+
215
+ if __name__ == "__main__": # pragma: no cover
216
+ sys.exit(main())