@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.
- package/.agent-src/commands/agent-handoff.md +4 -1
- package/.agent-src/commands/agent-status.md +3 -0
- package/.agent-src/commands/agents-audit.md +4 -0
- package/.agent-src/commands/agents-cleanup.md +6 -1
- package/.agent-src/commands/agents-prepare.md +3 -0
- package/.agent-src/commands/analyze-reference-repo.md +4 -0
- package/.agent-src/commands/bug-fix.md +7 -3
- package/.agent-src/commands/bug-investigate.md +4 -0
- package/.agent-src/commands/chat-history-checkpoint.md +126 -0
- package/.agent-src/commands/chat-history-clear.md +6 -1
- package/.agent-src/commands/chat-history-resume.md +7 -2
- package/.agent-src/commands/chat-history.md +7 -2
- package/.agent-src/commands/check-current-md.md +137 -0
- package/.agent-src/commands/commit-in-chunks.md +118 -0
- package/.agent-src/commands/commit.md +4 -0
- package/.agent-src/commands/compress.md +37 -2
- package/.agent-src/commands/context-create.md +4 -0
- package/.agent-src/commands/context-refactor.md +4 -0
- package/.agent-src/commands/copilot-agents-init.md +3 -0
- package/.agent-src/commands/copilot-agents-optimize.md +3 -0
- package/.agent-src/commands/create-pr-description.md +4 -0
- package/.agent-src/commands/create-pr.md +4 -0
- package/.agent-src/commands/do-and-judge.md +4 -1
- package/.agent-src/commands/do-in-steps.md +3 -0
- package/.agent-src/commands/e2e-heal.md +4 -0
- package/.agent-src/commands/e2e-plan.md +4 -0
- package/.agent-src/commands/estimate-ticket.md +4 -1
- package/.agent-src/commands/feature-dev.md +4 -0
- package/.agent-src/commands/feature-explore.md +4 -0
- package/.agent-src/commands/feature-plan.md +4 -0
- package/.agent-src/commands/feature-refactor.md +4 -0
- package/.agent-src/commands/feature-roadmap.md +6 -0
- package/.agent-src/commands/fix-ci.md +4 -0
- package/.agent-src/commands/fix-portability.md +5 -2
- package/.agent-src/commands/fix-pr-bot-comments.md +4 -0
- package/.agent-src/commands/fix-pr-comments.md +4 -0
- package/.agent-src/commands/fix-pr-developer-comments.md +4 -0
- package/.agent-src/commands/fix-references.md +3 -0
- package/.agent-src/commands/fix-seeder.md +4 -0
- package/.agent-src/commands/implement-ticket.md +39 -13
- package/.agent-src/commands/jira-ticket.md +4 -0
- package/.agent-src/commands/judge.md +3 -0
- package/.agent-src/commands/memory-add.md +5 -3
- package/.agent-src/commands/memory-full.md +5 -2
- package/.agent-src/commands/memory-promote.md +7 -6
- package/.agent-src/commands/mode.md +3 -0
- package/.agent-src/commands/module-create.md +4 -0
- package/.agent-src/commands/module-explore.md +4 -0
- package/.agent-src/commands/onboard.md +33 -0
- package/.agent-src/commands/optimize-agents.md +4 -0
- package/.agent-src/commands/optimize-augmentignore.md +12 -0
- package/.agent-src/commands/optimize-rtk-filters.md +3 -0
- package/.agent-src/commands/optimize-skills.md +4 -0
- package/.agent-src/commands/override-create.md +4 -0
- package/.agent-src/commands/override-manage.md +4 -0
- package/.agent-src/commands/package-reset.md +3 -0
- package/.agent-src/commands/package-test.md +3 -0
- package/.agent-src/commands/prepare-for-review.md +4 -0
- package/.agent-src/commands/project-analyze.md +4 -0
- package/.agent-src/commands/project-health.md +4 -0
- package/.agent-src/commands/propose-memory.md +6 -8
- package/.agent-src/commands/quality-fix.md +4 -0
- package/.agent-src/commands/refine-ticket.md +12 -7
- package/.agent-src/commands/review-changes.md +39 -8
- package/.agent-src/commands/review-routing.md +4 -0
- package/.agent-src/commands/roadmap-create.md +18 -0
- package/.agent-src/commands/roadmap-execute.md +14 -1
- package/.agent-src/commands/rule-compliance-audit.md +4 -0
- package/.agent-src/commands/set-cost-profile.md +11 -0
- package/.agent-src/commands/sync-agent-settings.md +12 -0
- package/.agent-src/commands/sync-gitignore.md +3 -0
- package/.agent-src/commands/tests-create.md +4 -0
- package/.agent-src/commands/tests-execute.md +6 -3
- package/.agent-src/commands/threat-model.md +4 -0
- package/.agent-src/commands/update-form-request-messages.md +4 -0
- package/.agent-src/commands/upstream-contribute.md +4 -0
- package/.agent-src/commands/work.md +161 -0
- package/.agent-src/guidelines/agent-infra/engineering-memory-data-format.md +2 -6
- package/.agent-src/guidelines/agent-infra/layered-settings.md +0 -1
- package/.agent-src/guidelines/agent-infra/memory-access.md +0 -7
- package/.agent-src/guidelines/agent-infra/role-contracts.md +2 -4
- package/.agent-src/guidelines/agent-infra/self-improvement-pipeline.md +0 -1
- package/.agent-src/guidelines/php/patterns/strategy.md +180 -2
- package/.agent-src/personas/README.md +0 -1
- package/.agent-src/rules/artifact-drafting-protocol.md +7 -2
- package/.agent-src/rules/artifact-engagement-recording.md +133 -0
- package/.agent-src/rules/ask-when-uncertain.md +18 -13
- package/.agent-src/rules/augment-portability.md +64 -37
- package/.agent-src/rules/autonomous-execution.md +158 -0
- package/.agent-src/rules/chat-history-cadence.md +109 -0
- package/.agent-src/rules/chat-history-ownership.md +123 -0
- package/.agent-src/rules/chat-history-visibility.md +96 -0
- package/.agent-src/rules/cli-output-handling.md +27 -4
- package/.agent-src/rules/command-suggestion.md +134 -0
- package/.agent-src/rules/commit-policy.md +109 -0
- package/.agent-src/rules/direct-answers.md +114 -0
- package/.agent-src/rules/docs-sync.md +36 -0
- package/.agent-src/rules/downstream-changes.md +10 -9
- package/.agent-src/rules/improve-before-implement.md +9 -6
- package/.agent-src/rules/language-and-tone.md +85 -6
- package/.agent-src/rules/non-destructive-by-default.md +117 -0
- package/.agent-src/rules/package-ci-checks.md +4 -0
- package/.agent-src/rules/preservation-guard.md +20 -0
- package/.agent-src/rules/roadmap-progress-sync.md +159 -27
- package/.agent-src/rules/role-mode-adherence.md +1 -1
- package/.agent-src/rules/scope-control.md +42 -1
- package/.agent-src/rules/size-enforcement.md +2 -3
- package/.agent-src/rules/skill-quality.md +3 -8
- package/.agent-src/rules/ui-audit-before-build.md +106 -0
- package/.agent-src/rules/user-interaction.md +107 -51
- package/.agent-src/scripts/update_roadmap_progress.py +73 -9
- package/.agent-src/skills/blade-ui/SKILL.md +47 -3
- package/.agent-src/skills/command-routing/SKILL.md +32 -0
- package/.agent-src/skills/command-writing/SKILL.md +52 -2
- package/.agent-src/skills/description-assist/SKILL.md +21 -0
- package/.agent-src/skills/estimate-ticket/SKILL.md +0 -1
- package/.agent-src/skills/existing-ui-audit/SKILL.md +202 -0
- package/.agent-src/skills/fe-design/SKILL.md +78 -61
- package/.agent-src/skills/file-editor/SKILL.md +9 -0
- package/.agent-src/skills/finishing-a-development-branch/SKILL.md +4 -0
- package/.agent-src/skills/flux/SKILL.md +31 -4
- package/.agent-src/skills/guideline-writing/SKILL.md +24 -2
- package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +51 -9
- package/.agent-src/skills/livewire/SKILL.md +49 -4
- package/.agent-src/skills/md-language-check/SKILL.md +103 -0
- package/.agent-src/skills/php-coder/SKILL.md +24 -0
- package/.agent-src/skills/react-shadcn-ui/SKILL.md +121 -0
- package/.agent-src/skills/refine-prompt/SKILL.md +220 -0
- package/.agent-src/skills/refine-ticket/SKILL.md +32 -28
- package/.agent-src/skills/roadmap-management/SKILL.md +24 -11
- package/.agent-src/skills/rule-writing/SKILL.md +23 -1
- package/.agent-src/skills/skill-writing/SKILL.md +3 -5
- package/.agent-src/skills/upstream-contribute/SKILL.md +3 -3
- package/.agent-src/skills/using-git-worktrees/SKILL.md +3 -1
- package/.agent-src/templates/AGENTS.md +24 -6
- package/.agent-src/templates/agent-settings.md +149 -0
- package/.agent-src/templates/roadmaps.md +11 -4
- package/.agent-src/templates/scripts/implement_ticket/__init__.py +63 -26
- package/.agent-src/templates/scripts/implement_ticket/__main__.py +8 -2
- package/.agent-src/templates/scripts/memory_lookup.py +1 -1
- package/.agent-src/templates/scripts/telemetry/__init__.py +42 -0
- package/.agent-src/templates/scripts/telemetry/aggregator.py +154 -0
- package/.agent-src/templates/scripts/telemetry/boundary.py +171 -0
- package/.agent-src/templates/scripts/telemetry/engagement.py +238 -0
- package/.agent-src/templates/scripts/telemetry/report_renderer.py +170 -0
- package/.agent-src/templates/scripts/telemetry/settings.py +112 -0
- package/.agent-src/templates/scripts/telemetry_record.py +166 -0
- package/.agent-src/templates/scripts/telemetry_report.py +161 -0
- package/.agent-src/templates/scripts/telemetry_status.py +142 -0
- package/.agent-src/templates/scripts/work_engine/__init__.py +58 -0
- package/.agent-src/templates/scripts/work_engine/__main__.py +9 -0
- package/.agent-src/templates/scripts/work_engine/cli.py +195 -0
- package/.agent-src/templates/scripts/work_engine/cli_args.py +116 -0
- package/.agent-src/templates/scripts/{implement_ticket → work_engine}/delivery_state.py +10 -3
- package/.agent-src/templates/scripts/work_engine/directives/__init__.py +33 -0
- package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +98 -0
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/analyze.py +1 -1
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/implement.py +3 -3
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/memory.py +2 -2
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/plan.py +2 -2
- package/.agent-src/templates/scripts/work_engine/directives/backend/refine.py +396 -0
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/report.py +37 -5
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/test.py +2 -2
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/verify.py +2 -2
- package/.agent-src/templates/scripts/work_engine/directives/mixed/__init__.py +116 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/contract.py +254 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/stitch.py +229 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/ui.py +231 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/__init__.py +113 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +44 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/apply.py +241 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/audit.py +414 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/design.py +335 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/polish.py +510 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/review.py +468 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/__init__.py +119 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.py +37 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.py +165 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.py +66 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/report.py +62 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/test.py +115 -0
- package/.agent-src/templates/scripts/work_engine/dispatcher.py +331 -0
- package/.agent-src/templates/scripts/work_engine/emitters.py +43 -0
- package/.agent-src/templates/scripts/work_engine/errors.py +19 -0
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +76 -0
- package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +54 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +32 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +103 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +44 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +42 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +50 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +49 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.py +53 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.py +50 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.py +52 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/trace.py +84 -0
- package/.agent-src/templates/scripts/work_engine/hooks/context.py +66 -0
- package/.agent-src/templates/scripts/work_engine/hooks/events.py +44 -0
- package/.agent-src/templates/scripts/work_engine/hooks/exceptions.py +79 -0
- package/.agent-src/templates/scripts/work_engine/hooks/registry.py +60 -0
- package/.agent-src/templates/scripts/work_engine/hooks/runner.py +73 -0
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +141 -0
- package/.agent-src/templates/scripts/work_engine/input_builders.py +163 -0
- package/.agent-src/templates/scripts/work_engine/intent/__init__.py +47 -0
- package/.agent-src/templates/scripts/work_engine/intent/classify.py +280 -0
- package/.agent-src/templates/scripts/work_engine/migration/__init__.py +8 -0
- package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +231 -0
- package/.agent-src/templates/scripts/{implement_ticket → work_engine}/persona_policy.py +1 -1
- package/.agent-src/templates/scripts/work_engine/resolvers/__init__.py +22 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/diff.py +106 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/file.py +113 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +90 -0
- package/.agent-src/templates/scripts/work_engine/scoring/__init__.py +14 -0
- package/.agent-src/templates/scripts/work_engine/scoring/confidence.py +300 -0
- package/.agent-src/templates/scripts/work_engine/stack/__init__.py +31 -0
- package/.agent-src/templates/scripts/work_engine/stack/detect.py +187 -0
- package/.agent-src/templates/scripts/work_engine/state.py +641 -0
- package/.agent-src/templates/scripts/work_engine/state_io.py +202 -0
- package/.claude-plugin/marketplace.json +105 -2
- package/AGENTS.md +38 -8
- package/CHANGELOG.md +609 -0
- package/README.md +136 -14
- package/config/agent-settings.template.yml +45 -0
- package/config/gitignore-block.txt +4 -0
- package/docs/MIGRATION.md +122 -0
- package/docs/architecture.md +111 -35
- package/docs/contracts/STABILITY.md +95 -0
- package/docs/contracts/adr-chat-history-split.md +132 -0
- package/docs/contracts/adr-command-suggestion.md +146 -0
- package/docs/contracts/adr-implement-ticket-runtime.md +122 -0
- package/docs/contracts/adr-product-ui-track.md +384 -0
- package/docs/contracts/adr-prompt-driven-execution.md +187 -0
- package/docs/contracts/agent-memory-contract.md +149 -0
- package/docs/contracts/artifact-engagement-flow.md +262 -0
- package/docs/contracts/command-clusters.md +126 -0
- package/docs/contracts/command-suggestion-flow.md +148 -0
- package/docs/contracts/implement-ticket-flow.md +628 -0
- package/docs/contracts/linear-ai-rules-inclusion.md +143 -0
- package/docs/contracts/linear-ai-three-layers.md +131 -0
- package/docs/contracts/rule-interactions.md +107 -0
- package/docs/contracts/rule-interactions.yml +142 -0
- package/docs/contracts/ui-stack-extension.md +236 -0
- package/docs/contracts/ui-track-flow.md +338 -0
- package/docs/development.md +1 -1
- package/docs/getting-started.md +3 -3
- package/docs/installation.md +124 -2
- package/docs/migrations/commands-1.15.0.md +112 -0
- package/docs/showcase.md +204 -0
- package/docs/ui-track-mental-model.md +121 -0
- package/package.json +1 -1
- package/scripts/agent-config +199 -0
- package/scripts/audit_cloud_compatibility.py +288 -0
- package/scripts/build_cloud_bundle.py +458 -0
- package/scripts/build_linear_digest.py +263 -0
- package/scripts/chat_history.py +796 -7
- package/scripts/check_compression.py +139 -0
- package/scripts/check_iron_law_prominence.py +143 -0
- package/scripts/check_md_language.py +159 -0
- package/scripts/check_portability.py +38 -0
- package/scripts/check_public_links.py +185 -0
- package/scripts/check_references.py +1 -0
- package/scripts/check_reply_consistency.py +140 -0
- package/scripts/command_suggester/__init__.py +51 -0
- package/scripts/command_suggester/cooldown.py +132 -0
- package/scripts/command_suggester/loader.py +70 -0
- package/scripts/command_suggester/match.py +180 -0
- package/scripts/command_suggester/rank.py +120 -0
- package/scripts/command_suggester/render.py +86 -0
- package/scripts/command_suggester/sanitize.py +113 -0
- package/scripts/command_suggester/settings.py +125 -0
- package/scripts/command_suggester/types.py +78 -0
- package/scripts/hooks/augment-chat-history.sh +56 -0
- package/scripts/install-hooks.sh +67 -0
- package/scripts/install.py +150 -33
- package/scripts/lint_marketplace.py +27 -0
- package/scripts/lint_no_new_atomic_commands.py +179 -0
- package/scripts/lint_rule_interactions.py +149 -0
- package/scripts/memory_lookup.py +1 -1
- package/scripts/migrate_command_suggestions.py +151 -0
- package/scripts/release.py +297 -64
- package/scripts/schemas/command.schema.json +41 -0
- package/scripts/skill_linter.py +81 -0
- package/scripts/sync_agent_settings.py +42 -12
- package/scripts/update_counts.py +10 -0
- package/templates/consumer-settings/augment-cli-hooks.json +54 -0
- package/templates/consumer-settings/claude-settings.json +55 -1
- package/.agent-src/rules/chat-history.md +0 -171
- package/.agent-src/templates/scripts/implement_ticket/cli.py +0 -171
- package/.agent-src/templates/scripts/implement_ticket/dispatcher.py +0 -134
- package/.agent-src/templates/scripts/implement_ticket/steps/__init__.py +0 -49
- package/.agent-src/templates/scripts/implement_ticket/steps/refine.py +0 -140
|
@@ -8,6 +8,8 @@ Checks that compression preserved structural integrity:
|
|
|
8
8
|
- All code blocks preserved exactly
|
|
9
9
|
- YAML frontmatter identical
|
|
10
10
|
- Word count reduction within healthy range (10-60%)
|
|
11
|
+
- Iron Law sections (## Iron Law / ### Iron Law / ## The Iron Law / Iron Laws / numbered)
|
|
12
|
+
preserved per `preservation-guard`: heading verbatim at original level, ≤ 15% reduction
|
|
11
13
|
|
|
12
14
|
Exit codes: 0 = clean, 1 = issues found, 3 = internal error
|
|
13
15
|
"""
|
|
@@ -60,6 +62,103 @@ def extract_frontmatter(text: str) -> str:
|
|
|
60
62
|
return m.group(1).strip() if m else ""
|
|
61
63
|
|
|
62
64
|
|
|
65
|
+
# Matches `## Iron Law`, `## The Iron Law`, `## Iron Laws`, `### Iron Law — …`,
|
|
66
|
+
# `## Iron Law 1 — …`, etc. Any heading level 2-6.
|
|
67
|
+
IRON_LAW_HEADING = re.compile(r"^(#{2,6})\s+(The\s+)?Iron Laws?\b")
|
|
68
|
+
|
|
69
|
+
LIST_ITEM_RE = re.compile(r"^(?:[-*+]|\d+\.)\s")
|
|
70
|
+
INNER_HEADING_RE = re.compile(r"^#{1,6}\s")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def count_iron_law_structure(body: str) -> dict:
|
|
74
|
+
"""Count structural units in an Iron Law body.
|
|
75
|
+
|
|
76
|
+
Returns counts of paragraphs (blank-line-separated prose blocks),
|
|
77
|
+
list items (bullet + numbered), and fenced code blocks. Caveman
|
|
78
|
+
compression may shorten word count freely; what must NOT change is
|
|
79
|
+
the count of these structural units. Each represents a passage of
|
|
80
|
+
the law that the source decided to keep.
|
|
81
|
+
|
|
82
|
+
Multi-line list items (bullet text wrapped to indented continuation
|
|
83
|
+
lines, no blank line between) count as ONE list item, not as a
|
|
84
|
+
list item plus a paragraph.
|
|
85
|
+
"""
|
|
86
|
+
paragraphs = 0
|
|
87
|
+
list_items = 0
|
|
88
|
+
code_blocks = 0
|
|
89
|
+
in_code = False
|
|
90
|
+
state = "blank" # "blank" | "paragraph" | "list"
|
|
91
|
+
for line in body.splitlines():
|
|
92
|
+
stripped = line.strip()
|
|
93
|
+
if stripped.startswith("```"):
|
|
94
|
+
if not in_code:
|
|
95
|
+
code_blocks += 1
|
|
96
|
+
in_code = not in_code
|
|
97
|
+
state = "blank"
|
|
98
|
+
continue
|
|
99
|
+
if in_code:
|
|
100
|
+
continue
|
|
101
|
+
if not stripped:
|
|
102
|
+
state = "blank"
|
|
103
|
+
continue
|
|
104
|
+
if LIST_ITEM_RE.match(stripped):
|
|
105
|
+
list_items += 1
|
|
106
|
+
state = "list"
|
|
107
|
+
continue
|
|
108
|
+
if INNER_HEADING_RE.match(stripped):
|
|
109
|
+
state = "blank"
|
|
110
|
+
continue
|
|
111
|
+
# Indented non-empty line right after a list item is a wrap
|
|
112
|
+
# continuation of that item, not a new paragraph.
|
|
113
|
+
if state == "list" and line.startswith((" ", "\t")):
|
|
114
|
+
continue
|
|
115
|
+
if state != "paragraph":
|
|
116
|
+
paragraphs += 1
|
|
117
|
+
state = "paragraph"
|
|
118
|
+
return {"paragraphs": paragraphs, "list_items": list_items, "code_blocks": code_blocks}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def extract_iron_law_sections(text: str) -> list[tuple[str, int, str]]:
|
|
122
|
+
"""Return [(heading, level, body)] for each Iron Law section.
|
|
123
|
+
|
|
124
|
+
Body is everything after the heading until the next heading at the same
|
|
125
|
+
or higher (numerically lower) level — fenced code blocks included verbatim.
|
|
126
|
+
"""
|
|
127
|
+
lines = text.splitlines()
|
|
128
|
+
sections: list[tuple[str, int, str]] = []
|
|
129
|
+
i = 0
|
|
130
|
+
in_code = False
|
|
131
|
+
while i < len(lines):
|
|
132
|
+
line = lines[i]
|
|
133
|
+
if line.strip().startswith("```"):
|
|
134
|
+
in_code = not in_code
|
|
135
|
+
i += 1
|
|
136
|
+
continue
|
|
137
|
+
if not in_code:
|
|
138
|
+
m = IRON_LAW_HEADING.match(line)
|
|
139
|
+
if m:
|
|
140
|
+
heading = line.rstrip()
|
|
141
|
+
level = len(m.group(1))
|
|
142
|
+
body_lines: list[str] = []
|
|
143
|
+
j = i + 1
|
|
144
|
+
inner_code = False
|
|
145
|
+
while j < len(lines):
|
|
146
|
+
jline = lines[j]
|
|
147
|
+
if jline.strip().startswith("```"):
|
|
148
|
+
inner_code = not inner_code
|
|
149
|
+
if not inner_code:
|
|
150
|
+
hm = re.match(r"^(#{1,6})\s", jline)
|
|
151
|
+
if hm and len(hm.group(1)) <= level:
|
|
152
|
+
break
|
|
153
|
+
body_lines.append(jline)
|
|
154
|
+
j += 1
|
|
155
|
+
sections.append((heading, level, "\n".join(body_lines)))
|
|
156
|
+
i = j
|
|
157
|
+
continue
|
|
158
|
+
i += 1
|
|
159
|
+
return sections
|
|
160
|
+
|
|
161
|
+
|
|
63
162
|
def check_pair(rel_path: str, source: str, compressed: str) -> List[Issue]:
|
|
64
163
|
"""Compare source and compressed versions of a file."""
|
|
65
164
|
issues: List[Issue] = []
|
|
@@ -96,6 +195,46 @@ def check_pair(rel_path: str, source: str, compressed: str) -> List[Issue]:
|
|
|
96
195
|
issues.append(Issue(rel_path, "modified_code_block", "error",
|
|
97
196
|
f"Code block {i+1} content changed during compression"))
|
|
98
197
|
|
|
198
|
+
# Iron Law preservation — non-negotiable behavioral rules, see preservation-guard
|
|
199
|
+
src_laws = extract_iron_law_sections(source)
|
|
200
|
+
cmp_laws = extract_iron_law_sections(compressed)
|
|
201
|
+
cmp_law_map = {h: (lvl, body) for h, lvl, body in cmp_laws}
|
|
202
|
+
# Build a level-agnostic lookup so we can detect heading-level downgrades
|
|
203
|
+
# (`## Iron Law` → `### Iron Law`).
|
|
204
|
+
cmp_law_by_text = {h.lstrip("# ").strip(): (lvl, h, body)
|
|
205
|
+
for h, lvl, body in cmp_laws}
|
|
206
|
+
for src_heading, src_level, src_body in src_laws:
|
|
207
|
+
src_text = src_heading.lstrip("# ").strip()
|
|
208
|
+
if src_heading not in cmp_law_map:
|
|
209
|
+
# Heading text may exist at a different level → downgrade
|
|
210
|
+
if src_text in cmp_law_by_text:
|
|
211
|
+
cmp_level, cmp_heading, _ = cmp_law_by_text[src_text]
|
|
212
|
+
if cmp_level != src_level:
|
|
213
|
+
issues.append(Issue(rel_path, "iron_law_heading_downgrade", "error",
|
|
214
|
+
f"Iron Law heading level changed: "
|
|
215
|
+
f"{'#' * src_level} → {'#' * cmp_level} "
|
|
216
|
+
f"({src_heading.strip()})"))
|
|
217
|
+
continue
|
|
218
|
+
issues.append(Issue(rel_path, "iron_law_missing", "error",
|
|
219
|
+
f"Iron Law section removed during compression: "
|
|
220
|
+
f"{src_heading.strip()}"))
|
|
221
|
+
continue
|
|
222
|
+
# Section exists at correct level — check structural-unit survival.
|
|
223
|
+
# Caveman compression is fine (drop articles, terse phrasing); what
|
|
224
|
+
# must NOT change is the count of paragraphs, list items, and code
|
|
225
|
+
# blocks. Each is a passage the source kept on purpose.
|
|
226
|
+
_, cmp_body = cmp_law_map[src_heading]
|
|
227
|
+
src_struct = count_iron_law_structure(src_body)
|
|
228
|
+
cmp_struct = count_iron_law_structure(cmp_body)
|
|
229
|
+
for kind, src_n in src_struct.items():
|
|
230
|
+
cmp_n = cmp_struct[kind]
|
|
231
|
+
if cmp_n < src_n:
|
|
232
|
+
issues.append(Issue(rel_path, "iron_law_passage_dropped", "error",
|
|
233
|
+
f"Iron Law section dropped "
|
|
234
|
+
f"{src_n - cmp_n} {kind} "
|
|
235
|
+
f"({src_n} → {cmp_n}): "
|
|
236
|
+
f"{src_heading.strip()}"))
|
|
237
|
+
|
|
99
238
|
# Word count ratio
|
|
100
239
|
src_words = len(source.split())
|
|
101
240
|
cmp_words = len(compressed.split())
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Iron Law prominence checker — enforces that any rule file declaring an
|
|
4
|
+
"Iron Law" places it at the top of the file at H2 level.
|
|
5
|
+
|
|
6
|
+
Rules:
|
|
7
|
+
1. No heading at H3 or deeper may match "Iron Law(s)" — Iron Laws must
|
|
8
|
+
be H2 sections, never sub-sections.
|
|
9
|
+
2. If a file declares one or more Iron-Law H2 sections, at least one
|
|
10
|
+
of them must be among the first two H2 headings of the file.
|
|
11
|
+
|
|
12
|
+
Files with no Iron-Law heading at all are exempt — they may legitimately
|
|
13
|
+
reference Iron Laws from other rules in prose only.
|
|
14
|
+
|
|
15
|
+
Code blocks are skipped to avoid false positives on quoted text.
|
|
16
|
+
|
|
17
|
+
Exit codes: 0 = clean, 1 = violations found, 3 = internal error.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import json
|
|
24
|
+
import re
|
|
25
|
+
import sys
|
|
26
|
+
from dataclasses import dataclass, asdict
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
HEADING_RE = re.compile(r"^(#{1,6})\s+(.+?)\s*$")
|
|
30
|
+
IRON_LAW_RE = re.compile(r"\biron\s+laws?\b", re.IGNORECASE)
|
|
31
|
+
FENCE_RE = re.compile(r"^\s*```")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Violation:
|
|
36
|
+
file: str
|
|
37
|
+
line: int
|
|
38
|
+
kind: str # "deep_iron_law" | "buried_iron_law"
|
|
39
|
+
detail: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _parse_headings(text: str) -> list[tuple[int, int, str]]:
|
|
43
|
+
"""Return (line_no, depth, title) for each heading outside code fences."""
|
|
44
|
+
headings: list[tuple[int, int, str]] = []
|
|
45
|
+
in_fence = False
|
|
46
|
+
for lineno, raw in enumerate(text.splitlines(), start=1):
|
|
47
|
+
if FENCE_RE.match(raw):
|
|
48
|
+
in_fence = not in_fence
|
|
49
|
+
continue
|
|
50
|
+
if in_fence:
|
|
51
|
+
continue
|
|
52
|
+
m = HEADING_RE.match(raw)
|
|
53
|
+
if not m:
|
|
54
|
+
continue
|
|
55
|
+
depth = len(m.group(1))
|
|
56
|
+
title = m.group(2).strip()
|
|
57
|
+
headings.append((lineno, depth, title))
|
|
58
|
+
return headings
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def scan_file(path: Path) -> list[Violation]:
|
|
62
|
+
text = path.read_text(encoding="utf-8")
|
|
63
|
+
headings = _parse_headings(text)
|
|
64
|
+
|
|
65
|
+
violations: list[Violation] = []
|
|
66
|
+
|
|
67
|
+
# Rule 1: no Iron Law at H3 or deeper
|
|
68
|
+
for lineno, depth, title in headings:
|
|
69
|
+
if depth >= 3 and IRON_LAW_RE.search(title):
|
|
70
|
+
violations.append(Violation(
|
|
71
|
+
file=str(path), line=lineno, kind="deep_iron_law",
|
|
72
|
+
detail=f"H{depth} heading `{title}` — promote to H2",
|
|
73
|
+
))
|
|
74
|
+
|
|
75
|
+
# Rule 2: if any H2 Iron Law exists, it must be in first 2 H2 positions
|
|
76
|
+
h2 = [(ln, t) for ln, d, t in headings if d == 2]
|
|
77
|
+
iron_h2 = [(ln, t) for ln, t in h2 if IRON_LAW_RE.search(t)]
|
|
78
|
+
if iron_h2:
|
|
79
|
+
first_two_lines = {ln for ln, _ in h2[:2]}
|
|
80
|
+
if not any(ln in first_two_lines for ln, _ in iron_h2):
|
|
81
|
+
first_iron_ln, first_iron_title = iron_h2[0]
|
|
82
|
+
preceding = [t for ln, t in h2 if ln < first_iron_ln]
|
|
83
|
+
violations.append(Violation(
|
|
84
|
+
file=str(path), line=first_iron_ln, kind="buried_iron_law",
|
|
85
|
+
detail=(
|
|
86
|
+
f"Iron Law H2 `{first_iron_title}` at line {first_iron_ln} "
|
|
87
|
+
f"is preceded by {len(preceding)} non-Iron-Law H2 section(s): "
|
|
88
|
+
f"{preceding}. Move Iron Law into the first 2 H2 positions."
|
|
89
|
+
),
|
|
90
|
+
))
|
|
91
|
+
|
|
92
|
+
return violations
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _resolve_targets(paths: list[str]) -> list[Path]:
|
|
96
|
+
out: list[Path] = []
|
|
97
|
+
for raw in paths:
|
|
98
|
+
p = Path(raw)
|
|
99
|
+
if p.is_dir():
|
|
100
|
+
out.extend(sorted(p.rglob("*.md")))
|
|
101
|
+
elif p.suffix == ".md":
|
|
102
|
+
out.append(p)
|
|
103
|
+
return out
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main() -> int:
|
|
107
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"paths", nargs="*",
|
|
110
|
+
default=[".agent-src.uncompressed/rules"],
|
|
111
|
+
help="Files or directories to scan (default: .agent-src.uncompressed/rules)",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
114
|
+
args = parser.parse_args()
|
|
115
|
+
|
|
116
|
+
targets = _resolve_targets(args.paths)
|
|
117
|
+
all_violations: list[Violation] = []
|
|
118
|
+
for path in targets:
|
|
119
|
+
if not path.exists():
|
|
120
|
+
print(f"⚠️ Not found: {path}", file=sys.stderr)
|
|
121
|
+
continue
|
|
122
|
+
all_violations.extend(scan_file(path))
|
|
123
|
+
|
|
124
|
+
if args.format == "json":
|
|
125
|
+
print(json.dumps([asdict(v) for v in all_violations], indent=2, ensure_ascii=False))
|
|
126
|
+
else:
|
|
127
|
+
if not all_violations:
|
|
128
|
+
print(f"✅ Iron Law prominence clean ({len(targets)} file(s) scanned).")
|
|
129
|
+
else:
|
|
130
|
+
print(f"❌ {len(all_violations)} Iron-Law prominence violation(s):\n")
|
|
131
|
+
for v in all_violations:
|
|
132
|
+
print(f" {v.file}:{v.line} — {v.kind}")
|
|
133
|
+
print(f" │ {v.detail}")
|
|
134
|
+
|
|
135
|
+
return 1 if all_violations else 0
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
try:
|
|
140
|
+
sys.exit(main())
|
|
141
|
+
except Exception as exc: # noqa: BLE001
|
|
142
|
+
print(f"❌ Internal error: {exc}", file=sys.stderr)
|
|
143
|
+
sys.exit(3)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Markdown language checker — enforces language-and-tone § ".md files are ALWAYS English".
|
|
4
|
+
|
|
5
|
+
Scans .md files for German content (umlauts, function words, quoted DE phrases)
|
|
6
|
+
in body prose, skipping:
|
|
7
|
+
- Fenced code blocks (``` ... ```)
|
|
8
|
+
- Inline code (`...`)
|
|
9
|
+
- Labeled DE: ... · EN: ... anchor blocks
|
|
10
|
+
- URLs and file paths inside backticks
|
|
11
|
+
|
|
12
|
+
Exit codes: 0 = clean, 1 = violations found, 3 = internal error.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import re
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import dataclass, asdict
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
# Umlauts and German-only characters
|
|
25
|
+
UMLAUT_RE = re.compile(r"[äöüÄÖÜß]")
|
|
26
|
+
|
|
27
|
+
# German function words that almost never appear in English technical prose
|
|
28
|
+
DE_WORDS = [
|
|
29
|
+
"für", "nicht", "dass", "wenn", "sollte", "werden", "arbeite",
|
|
30
|
+
"selbstständig", "jetzt", "einfach", "weiter", "lösche", "frag",
|
|
31
|
+
"schreib", "mach", "auch", "hier", "diese", "dieser", "dieses",
|
|
32
|
+
"vermutlich", "bitte", "kannst", "sollen", "müssen", "wäre",
|
|
33
|
+
]
|
|
34
|
+
DE_WORD_RE = re.compile(
|
|
35
|
+
r"\b(" + "|".join(re.escape(w) for w in DE_WORDS) + r")\b",
|
|
36
|
+
re.IGNORECASE,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Labeled bilingual anchor: lines starting with "DE:" or "- DE:" (and same for EN)
|
|
40
|
+
DE_ANCHOR_RE = re.compile(r"^\s*[-*]?\s*(DE|EN):\s", re.IGNORECASE)
|
|
41
|
+
|
|
42
|
+
# Inline code spans
|
|
43
|
+
INLINE_CODE_RE = re.compile(r"`[^`]*`")
|
|
44
|
+
|
|
45
|
+
# Per-line escape: append `<!-- md-language-check: ignore -->` to a line
|
|
46
|
+
# to suppress findings on that line. For meta-documentation that quotes
|
|
47
|
+
# German tokens as trigger examples (e.g. inside language-and-tone.md).
|
|
48
|
+
IGNORE_RE = re.compile(r"<!--\s*md-language-check:\s*ignore\s*-->", re.IGNORECASE)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Violation:
|
|
53
|
+
file: str
|
|
54
|
+
line: int
|
|
55
|
+
kind: str # "umlaut" | "de_word"
|
|
56
|
+
match: str
|
|
57
|
+
context: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _strip_inline_code(text: str) -> str:
|
|
61
|
+
return INLINE_CODE_RE.sub("", text)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def scan_file(path: Path) -> list[Violation]:
|
|
65
|
+
violations: list[Violation] = []
|
|
66
|
+
try:
|
|
67
|
+
lines = path.read_text(encoding="utf-8").splitlines()
|
|
68
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
69
|
+
print(f"⚠️ Cannot read {path}: {exc}", file=sys.stderr)
|
|
70
|
+
return violations
|
|
71
|
+
|
|
72
|
+
in_fence = False
|
|
73
|
+
in_frontmatter = False
|
|
74
|
+
for lineno, raw in enumerate(lines, start=1):
|
|
75
|
+
stripped = raw.lstrip()
|
|
76
|
+
|
|
77
|
+
# YAML frontmatter at top of file
|
|
78
|
+
if lineno == 1 and stripped == "---":
|
|
79
|
+
in_frontmatter = True
|
|
80
|
+
continue
|
|
81
|
+
if in_frontmatter:
|
|
82
|
+
if stripped == "---":
|
|
83
|
+
in_frontmatter = False
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
# Fenced code blocks
|
|
87
|
+
if stripped.startswith("```") or stripped.startswith("~~~"):
|
|
88
|
+
in_fence = not in_fence
|
|
89
|
+
continue
|
|
90
|
+
if in_fence:
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
# Indented code blocks (4+ leading spaces, non-list)
|
|
94
|
+
if raw.startswith(" ") and not stripped.startswith(("-", "*", "+", "1", "2", "3", "4", "5", "6", "7", "8", "9")):
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
# Labeled bilingual anchor — allowed location for DE prose
|
|
98
|
+
if DE_ANCHOR_RE.match(raw):
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Per-line opt-out marker
|
|
102
|
+
if IGNORE_RE.search(raw):
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
# Strip inline code spans before scanning
|
|
106
|
+
scan_text = _strip_inline_code(raw)
|
|
107
|
+
|
|
108
|
+
for m in UMLAUT_RE.finditer(scan_text):
|
|
109
|
+
violations.append(Violation(
|
|
110
|
+
file=str(path), line=lineno, kind="umlaut",
|
|
111
|
+
match=m.group(0), context=raw.rstrip(),
|
|
112
|
+
))
|
|
113
|
+
|
|
114
|
+
for m in DE_WORD_RE.finditer(scan_text):
|
|
115
|
+
violations.append(Violation(
|
|
116
|
+
file=str(path), line=lineno, kind="de_word",
|
|
117
|
+
match=m.group(0), context=raw.rstrip(),
|
|
118
|
+
))
|
|
119
|
+
|
|
120
|
+
return violations
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def main() -> int:
|
|
124
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
125
|
+
parser.add_argument("paths", nargs="+", help="One or more .md files to scan")
|
|
126
|
+
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
127
|
+
args = parser.parse_args()
|
|
128
|
+
|
|
129
|
+
all_violations: list[Violation] = []
|
|
130
|
+
for raw_path in args.paths:
|
|
131
|
+
path = Path(raw_path)
|
|
132
|
+
if not path.exists():
|
|
133
|
+
print(f"⚠️ Not found: {path}", file=sys.stderr)
|
|
134
|
+
continue
|
|
135
|
+
if path.suffix != ".md":
|
|
136
|
+
print(f"⚠️ Skipping non-.md: {path}", file=sys.stderr)
|
|
137
|
+
continue
|
|
138
|
+
all_violations.extend(scan_file(path))
|
|
139
|
+
|
|
140
|
+
if args.format == "json":
|
|
141
|
+
print(json.dumps([asdict(v) for v in all_violations], indent=2, ensure_ascii=False))
|
|
142
|
+
else:
|
|
143
|
+
if not all_violations:
|
|
144
|
+
print("✅ No German content detected.")
|
|
145
|
+
else:
|
|
146
|
+
print(f"❌ {len(all_violations)} violation(s) found:\n")
|
|
147
|
+
for v in all_violations:
|
|
148
|
+
print(f" {v.file}:{v.line} — {v.kind} `{v.match}`")
|
|
149
|
+
print(f" │ {v.context}")
|
|
150
|
+
|
|
151
|
+
return 1 if all_violations else 0
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
try:
|
|
156
|
+
sys.exit(main())
|
|
157
|
+
except Exception as exc: # noqa: BLE001
|
|
158
|
+
print(f"❌ Internal error: {exc}", file=sys.stderr)
|
|
159
|
+
sys.exit(3)
|
|
@@ -157,6 +157,8 @@ ALLOWLIST = [
|
|
|
157
157
|
r"agent-config", # refers to the package concept, not a specific project
|
|
158
158
|
r"shared.*package", # "shared package" concept
|
|
159
159
|
r"package repository", # "package repository" concept
|
|
160
|
+
r"scripts/mcp_server/", # MCP server module path (road-to-mcp-server.md Phase 1)
|
|
161
|
+
r"scripts\.mcp_server", # MCP server Python module entrypoint
|
|
160
162
|
]
|
|
161
163
|
|
|
162
164
|
# Directories to scan (only package files, not project-specific agents/)
|
|
@@ -329,6 +331,42 @@ _CLI_INVOCATION_MAP: list[tuple[re.Pattern, str]] = [
|
|
|
329
331
|
re.compile(r"bash\s+scripts/first-run\.sh\b"),
|
|
330
332
|
"./agent-config first-run",
|
|
331
333
|
),
|
|
334
|
+
(
|
|
335
|
+
re.compile(r"(?:PYTHONPATH=\S+\s+)?python3\s+-m\s+work_engine\b"),
|
|
336
|
+
"./agent-config implement-ticket",
|
|
337
|
+
),
|
|
338
|
+
(
|
|
339
|
+
re.compile(r"(?:PYTHONPATH=\S+\s+)?python3\s+-m\s+implement_ticket\b"),
|
|
340
|
+
"./agent-config implement-ticket",
|
|
341
|
+
),
|
|
342
|
+
(
|
|
343
|
+
re.compile(r"python3\s+scripts/memory_lookup\.py\b"),
|
|
344
|
+
"./agent-config memory:lookup",
|
|
345
|
+
),
|
|
346
|
+
(
|
|
347
|
+
re.compile(r"python3\s+scripts/memory_signal\.py\b"),
|
|
348
|
+
"./agent-config memory:signal",
|
|
349
|
+
),
|
|
350
|
+
(
|
|
351
|
+
re.compile(r"python3\s+scripts/memory_hash\.py\b"),
|
|
352
|
+
"./agent-config memory:hash",
|
|
353
|
+
),
|
|
354
|
+
(
|
|
355
|
+
re.compile(r"python3\s+scripts/check_memory_proposal\.py\b"),
|
|
356
|
+
"./agent-config memory:check-proposal",
|
|
357
|
+
),
|
|
358
|
+
(
|
|
359
|
+
re.compile(r"python3\s+scripts/check_memory\.py\b"),
|
|
360
|
+
"./agent-config memory:check",
|
|
361
|
+
),
|
|
362
|
+
(
|
|
363
|
+
re.compile(r"python3\s+scripts/check_proposal\.py\b"),
|
|
364
|
+
"./agent-config proposal:check",
|
|
365
|
+
),
|
|
366
|
+
(
|
|
367
|
+
re.compile(r"python3\s+scripts/refine_ticket_detect\.py\b"),
|
|
368
|
+
"./agent-config refine-ticket:detect",
|
|
369
|
+
),
|
|
332
370
|
]
|
|
333
371
|
|
|
334
372
|
# Paths that legitimately document the raw invocations (e.g. the CLI's
|