@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,263 @@
1
+ #!/usr/bin/env python3
2
+ """build_linear_digest.py — build the Linear AI rules digest.
3
+
4
+ Concatenates a curated set of cloud-safe rules from
5
+ `.agent-src.uncompressed/rules/` into three Markdown files under
6
+ `dist/linear/`:
7
+
8
+ workspace.md — universal coding posture (18 rules)
9
+ team.md — framework-specific (4 rules; paste only where stack matches)
10
+ personal.md — empty stub for individual preferences
11
+
12
+ Per-rule inclusion + mode is the source of truth in
13
+ `docs/contracts/linear-ai-rules-inclusion.md`. This script encodes the
14
+ same lists so a drift between the two surfaces is caught by the digest
15
+ audit (Phase 3 Step 4) — the markdown doc is the human-readable spec,
16
+ this script is the executable.
17
+
18
+ Transformations applied to every included rule:
19
+
20
+ 1. Strip YAML frontmatter.
21
+ 2. Demote the rule's H1 to H2 (H1 stays for the digest's own title).
22
+ 3. Replace `[text](path.md...)` links with plain `text` — paths do
23
+ not resolve outside the repo. External `http(s)` links are kept.
24
+ 4. For rules tagged ``degraded`` in DEGRADE_RULES, strip the named
25
+ H2/H3 sections (cloud-irrelevant content like `.agent-settings.yml`
26
+ references, rtk Iron Law, English-`.md`-files clause, etc.).
27
+
28
+ Outputs and exit code:
29
+
30
+ - Writes to dist/linear/{workspace,team,personal}.md
31
+ - Stdout: per-digest size summary (chars, rules, sections stripped)
32
+ - Exit 0 on success
33
+ - Exit 2 if any digest exceeds --max-bytes (Phase 3 Step 4 budget gate)
34
+ - Exit 3 if a referenced rule file is missing
35
+ """
36
+ from __future__ import annotations
37
+
38
+ import argparse
39
+ import re
40
+ import sys
41
+ from dataclasses import dataclass, field
42
+ from pathlib import Path
43
+
44
+ ROOT = Path(__file__).resolve().parent.parent
45
+ # Compressed source is the shipped form — denser, sharper section
46
+ # structure; better fit for a guidance field than the verbose authoring
47
+ # layer. The inclusion list at docs/contracts/linear-ai-rules-inclusion.md
48
+ # remains the human-readable spec.
49
+ SOURCE = ROOT / ".agent-src" / "rules"
50
+ OUT_DIR = ROOT / "dist" / "linear"
51
+
52
+ # Linear does not publish a hard cap on agent-guidance fields. 100 KB
53
+ # is generous for every observed agent surface (Linear Agent, Codegen,
54
+ # Charlie); tighten via --max-bytes once the actual cap is researched
55
+ # (Open Question #1 in road-to-universal-distribution.md).
56
+ DEFAULT_MAX_BYTES = 100_000
57
+
58
+
59
+ @dataclass
60
+ class RuleEntry:
61
+ name: str
62
+ mode: str = "as-is" # "as-is" | "degraded"
63
+ strip_sections: list[str] = field(default_factory=list)
64
+
65
+
66
+ # Workspace digest — universal coding posture. Maps 1:1 to the
67
+ # "Workspace digest" table in docs/contracts/linear-ai-rules-inclusion.md.
68
+ WORKSPACE: list[RuleEntry] = [
69
+ RuleEntry("ask-when-uncertain"),
70
+ RuleEntry("commit-conventions"),
71
+ RuleEntry("context-hygiene", "degraded",
72
+ strip_sections=["Augment-specific: Ignored Skills Recovery"]),
73
+ RuleEntry("direct-answers"),
74
+ RuleEntry("markdown-safe-codeblocks"),
75
+ RuleEntry("minimal-safe-diff"),
76
+ RuleEntry("reviewer-awareness"),
77
+ RuleEntry("scope-control"),
78
+ RuleEntry("security-sensitive-stop"),
79
+ RuleEntry("think-before-action", "degraded",
80
+ strip_sections=["Consult memory before editing"]),
81
+ RuleEntry("verify-before-complete"),
82
+ RuleEntry("cli-output-handling", "degraded",
83
+ strip_sections=["Iron Law — rtk first, tail/grep fallback"]),
84
+ RuleEntry("downstream-changes"),
85
+ RuleEntry("improve-before-implement"),
86
+ RuleEntry("language-and-tone", "degraded",
87
+ strip_sections=["`.md` files are ALWAYS English — no exceptions"]),
88
+ RuleEntry("missing-tool-handling"),
89
+ RuleEntry("token-efficiency"),
90
+ RuleEntry("user-interaction"),
91
+ ]
92
+
93
+ # Team digest — framework-specific. Stack already named in each rule's
94
+ # trigger line; no per-rule stripping required.
95
+ TEAM: list[RuleEntry] = [
96
+ RuleEntry("docker-commands"),
97
+ RuleEntry("laravel-translations"),
98
+ RuleEntry("e2e-testing"),
99
+ RuleEntry("php-coding"),
100
+ ]
101
+
102
+ # Personal digest is empty by default — just a stub.
103
+ PERSONAL: list[RuleEntry] = []
104
+
105
+ FRONTMATTER_RE = re.compile(r"^---\n.*?\n---\n", re.DOTALL)
106
+ LINK_RE = re.compile(r"\[([^\]]+)\]\((?!https?://)[^)]+\)")
107
+ H1_RE = re.compile(r"^# ", re.MULTILINE)
108
+
109
+
110
+ def strip_frontmatter(text: str) -> str:
111
+ return FRONTMATTER_RE.sub("", text, count=1).lstrip()
112
+
113
+
114
+ def demote_h1(text: str) -> str:
115
+ """Promote rule H1 to H2 so the digest H1 stays the only top-level."""
116
+ return H1_RE.sub("## ", text, count=1)
117
+
118
+
119
+ def normalize_links(text: str) -> str:
120
+ """Replace internal markdown links with their plain anchor text.
121
+
122
+ Internal = relative path or repo-rooted path. External http(s)
123
+ links are preserved verbatim.
124
+ """
125
+ return LINK_RE.sub(r"\1", text)
126
+
127
+
128
+ def strip_section(text: str, section_title: str) -> tuple[str, bool]:
129
+ """Strip an H2/H3 section by exact title match (without trailing comments)."""
130
+ pattern = re.compile(
131
+ rf"^(#{{2,3}})\s+{re.escape(section_title)}\s*\n.*?(?=^#{{1,3}}\s|\Z)",
132
+ re.DOTALL | re.MULTILINE,
133
+ )
134
+ new_text, count = pattern.subn("", text)
135
+ return new_text, count > 0
136
+
137
+
138
+ def render_rule(entry: RuleEntry) -> tuple[str, list[str]]:
139
+ """Render one rule as a digest section.
140
+
141
+ Returns (markdown, missing_sections). missing_sections is non-empty
142
+ when a strip_sections entry did not match — a likely drift signal
143
+ between this script and the source rule.
144
+ """
145
+ path = SOURCE / f"{entry.name}.md"
146
+ if not path.is_file():
147
+ raise FileNotFoundError(f"Rule source missing: {path}")
148
+
149
+ text = path.read_text(encoding="utf-8")
150
+ text = strip_frontmatter(text)
151
+ text = demote_h1(text)
152
+ text = normalize_links(text)
153
+
154
+ missing: list[str] = []
155
+ if entry.mode == "degraded":
156
+ for section in entry.strip_sections:
157
+ text, found = strip_section(text, section)
158
+ if not found:
159
+ missing.append(section)
160
+
161
+ # Collapse any double-blank-lines created by stripping.
162
+ text = re.sub(r"\n{3,}", "\n\n", text).rstrip() + "\n"
163
+ return text, missing
164
+
165
+
166
+ def render_digest(layer: str, entries: list[RuleEntry]) -> tuple[str, dict]:
167
+ parts: list[str] = []
168
+ parts.append(f"# event4u/agent-config — Linear AI {layer.title()} Digest\n")
169
+ parts.append(
170
+ "> Auto-generated by `scripts/build_linear_digest.py` from "
171
+ "`.agent-src/rules/` (compressed source) plus the inclusion list "
172
+ "at `docs/contracts/linear-ai-rules-inclusion.md`. Do not edit "
173
+ "this file by hand — re-run `task build-linear-digest` to "
174
+ "regenerate.\n"
175
+ )
176
+ if layer == "personal":
177
+ parts.append(
178
+ "\nPersonal guidance is intentionally empty — paste your own "
179
+ "preferences (response language overrides, IDE shortcuts, naming "
180
+ "conventions) below this line.\n"
181
+ )
182
+ return "".join(parts), {"layer": layer, "rules": 0, "missing": {}}
183
+
184
+ if not entries:
185
+ parts.append("\n_No rules in this digest._\n")
186
+ return "".join(parts), {"layer": layer, "rules": 0, "missing": {}}
187
+
188
+ parts.append(
189
+ f"\n_{len(entries)} rules included. Order matches the inclusion "
190
+ "list._\n\n---\n\n"
191
+ )
192
+
193
+ missing_per_rule: dict[str, list[str]] = {}
194
+ for i, entry in enumerate(entries):
195
+ body, missing = render_rule(entry)
196
+ if missing:
197
+ missing_per_rule[entry.name] = missing
198
+ parts.append(body)
199
+ if i < len(entries) - 1:
200
+ parts.append("\n---\n\n")
201
+
202
+ return "".join(parts), {
203
+ "layer": layer,
204
+ "rules": len(entries),
205
+ "missing": missing_per_rule,
206
+ }
207
+
208
+
209
+ def main(argv: list[str] | None = None) -> int:
210
+ p = argparse.ArgumentParser(description=__doc__.split("\n", 1)[0])
211
+ p.add_argument("--max-bytes", type=int, default=DEFAULT_MAX_BYTES,
212
+ help=f"per-digest byte budget (default {DEFAULT_MAX_BYTES})")
213
+ p.add_argument("--out-dir", type=Path, default=OUT_DIR,
214
+ help="output directory (default dist/linear/)")
215
+ p.add_argument("--strict-missing", action="store_true",
216
+ help="exit non-zero if a strip_sections title is unmatched")
217
+ args = p.parse_args(argv)
218
+
219
+ args.out_dir.mkdir(parents=True, exist_ok=True)
220
+
221
+ layers = [("workspace", WORKSPACE), ("team", TEAM), ("personal", PERSONAL)]
222
+ over_budget = False
223
+ drift = False
224
+
225
+ for layer, entries in layers:
226
+ try:
227
+ digest, summary = render_digest(layer, entries)
228
+ except FileNotFoundError as exc:
229
+ print(f"❌ {exc}", file=sys.stderr)
230
+ return 3
231
+
232
+ out_path = args.out_dir / f"{layer}.md"
233
+ out_path.write_text(digest, encoding="utf-8")
234
+ size = len(digest.encode("utf-8"))
235
+ flag = "⚠️ " if size > args.max_bytes else " "
236
+ try:
237
+ display_path = out_path.relative_to(ROOT)
238
+ except ValueError:
239
+ display_path = out_path
240
+ print(f"{flag}{layer:<10} {summary['rules']:>2} rules "
241
+ f"{size:>6} bytes {display_path}")
242
+ if size > args.max_bytes:
243
+ over_budget = True
244
+ if summary["missing"]:
245
+ drift = True
246
+ for name, sections in summary["missing"].items():
247
+ print(f" ⚠️ {name}: unmatched strip_sections: {sections}",
248
+ file=sys.stderr)
249
+
250
+ if over_budget:
251
+ print(f"❌ one or more digests exceed --max-bytes={args.max_bytes}",
252
+ file=sys.stderr)
253
+ return 2
254
+ if drift and args.strict_missing:
255
+ print("❌ --strict-missing: at least one strip_sections title did "
256
+ "not match (digest config drifted from rule source)",
257
+ file=sys.stderr)
258
+ return 4
259
+ return 0
260
+
261
+
262
+ if __name__ == "__main__":
263
+ sys.exit(main())