@event4u/agent-config 1.20.0 → 1.22.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/agents.md +1 -1
- package/.agent-src/commands/bug-fix.md +2 -1
- package/.agent-src/commands/bug-investigate.md +3 -2
- package/.agent-src/commands/challenge-me/vision.md +348 -0
- package/.agent-src/commands/challenge-me/with-docs.md +333 -0
- package/.agent-src/commands/challenge-me.md +61 -0
- package/.agent-src/commands/chat-history/import.md +60 -64
- package/.agent-src/commands/compress.md +12 -0
- package/.agent-src/commands/context/create.md +2 -2
- package/.agent-src/commands/context.md +1 -1
- package/.agent-src/commands/copilot-agents.md +1 -1
- package/.agent-src/commands/council/default.md +69 -10
- package/.agent-src/commands/council.md +1 -1
- package/.agent-src/commands/create-pr.md +7 -3
- package/.agent-src/commands/e2e-heal.md +1 -1
- package/.agent-src/commands/e2e-plan.md +1 -1
- package/.agent-src/commands/feature/dev.md +3 -3
- package/.agent-src/commands/feature.md +1 -1
- package/.agent-src/commands/fix/seeder.md +2 -2
- package/.agent-src/commands/fix.md +1 -1
- package/.agent-src/commands/grill-me.md +38 -0
- package/.agent-src/commands/jira-ticket.md +1 -1
- package/.agent-src/commands/judge/steps.md +1 -1
- package/.agent-src/commands/judge.md +2 -2
- package/.agent-src/commands/memory.md +1 -1
- package/.agent-src/commands/mode.md +5 -5
- package/.agent-src/commands/module.md +1 -1
- package/.agent-src/commands/onboard.md +4 -4
- package/.agent-src/commands/optimize/augmentignore.md +1 -1
- package/.agent-src/commands/optimize-prompt.md +61 -0
- package/.agent-src/commands/optimize.md +1 -1
- package/.agent-src/commands/override.md +1 -1
- package/.agent-src/commands/review-changes.md +1 -1
- package/.agent-src/commands/review-routing.md +1 -1
- package/.agent-src/commands/roadmap/ai-council.md +183 -0
- package/.agent-src/commands/roadmap/create.md +6 -1
- package/.agent-src/commands/roadmap/process-full.md +58 -0
- package/.agent-src/commands/roadmap/process-phase.md +69 -0
- package/.agent-src/commands/roadmap/process-step.md +57 -0
- package/.agent-src/commands/roadmap.md +45 -17
- package/.agent-src/commands/set-cost-profile.md +3 -3
- package/.agent-src/commands/sync-agent-settings.md +2 -2
- package/.agent-src/commands/tests/create.md +2 -2
- package/.agent-src/commands/tests.md +1 -1
- package/.agent-src/commands/threat-model.md +5 -4
- package/.agent-src/contexts/augment-infrastructure.md +1 -1
- package/.agent-src/contexts/authority/commit-mechanics.md +14 -1
- package/.agent-src/contexts/authority/destructive-mechanics.md +14 -1
- package/.agent-src/contexts/authority/scope-mechanics.md +5 -0
- package/.agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +76 -0
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +54 -19
- package/.agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +98 -0
- package/.agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +93 -0
- package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +128 -5
- package/.agent-src/contexts/execution/autonomy-mechanics.md +44 -0
- package/.agent-src/contexts/execution/roadmap-process-loop.md +125 -0
- package/.agent-src/contexts/model-recommendations.md +2 -2
- package/.agent-src/contexts/override-system.md +1 -1
- package/.agent-src/contexts/skills-and-commands.md +1 -1
- package/.agent-src/personas/product-owner.md +2 -2
- package/.agent-src/personas/qa.md +1 -1
- package/.agent-src/rules/agent-authority.md +5 -6
- package/.agent-src/rules/agent-docs.md +11 -53
- package/.agent-src/rules/analysis-skill-routing.md +10 -40
- package/.agent-src/rules/architecture.md +6 -1
- package/.agent-src/rules/artifact-drafting-protocol.md +5 -0
- package/.agent-src/rules/artifact-engagement-recording.md +23 -59
- package/.agent-src/rules/ask-when-uncertain.md +24 -47
- package/.agent-src/rules/augment-portability.md +14 -62
- package/.agent-src/rules/augment-source-of-truth.md +10 -1
- package/.agent-src/rules/autonomous-execution.md +17 -98
- package/.agent-src/rules/capture-learnings.md +9 -80
- package/.agent-src/rules/cli-output-handling.md +12 -42
- package/.agent-src/rules/command-suggestion-policy.md +25 -73
- package/.agent-src/rules/commit-conventions.md +9 -58
- package/.agent-src/rules/commit-policy.md +16 -47
- package/.agent-src/rules/context-hygiene.md +5 -0
- package/.agent-src/rules/direct-answers.md +21 -50
- package/.agent-src/rules/docker-commands.md +11 -45
- package/.agent-src/rules/docs-sync.md +10 -56
- package/.agent-src/rules/downstream-changes.md +5 -0
- package/.agent-src/rules/e2e-testing.md +9 -44
- package/.agent-src/rules/guidelines.md +13 -75
- package/.agent-src/rules/improve-before-implement.md +11 -2
- package/.agent-src/rules/invite-challenge.md +71 -0
- package/.agent-src/rules/language-and-tone.md +41 -106
- package/.agent-src/rules/laravel-translations.md +11 -40
- package/.agent-src/rules/markdown-safe-codeblocks.md +4 -0
- package/.agent-src/rules/minimal-safe-diff.md +4 -0
- package/.agent-src/rules/missing-tool-handling.md +4 -0
- package/.agent-src/rules/model-recommendation.md +9 -61
- package/.agent-src/rules/no-attribution-footers.md +5 -0
- package/.agent-src/rules/no-cheap-questions.md +11 -27
- package/.agent-src/rules/no-council-references.md +76 -0
- package/.agent-src/rules/no-roadmap-references.md +7 -0
- package/.agent-src/rules/non-destructive-by-default.md +13 -43
- package/.agent-src/rules/onboarding-gate.md +9 -117
- package/.agent-src/rules/package-ci-checks.md +10 -37
- package/.agent-src/rules/php-coding.md +10 -55
- package/.agent-src/rules/preservation-guard.md +9 -0
- package/.agent-src/rules/review-routing-awareness.md +9 -97
- package/.agent-src/rules/reviewer-awareness.md +8 -83
- package/.agent-src/rules/roadmap-progress-sync.md +7 -170
- package/.agent-src/rules/role-mode-adherence.md +6 -2
- package/.agent-src/rules/rule-type-governance.md +8 -66
- package/.agent-src/rules/runtime-safety.md +5 -0
- package/.agent-src/rules/scope-control.md +17 -62
- package/.agent-src/rules/security-sensitive-stop.md +7 -1
- package/.agent-src/rules/size-enforcement.md +6 -1
- package/.agent-src/rules/skill-improvement-trigger.md +9 -49
- package/.agent-src/rules/skill-quality.md +7 -113
- package/.agent-src/rules/slash-command-routing-policy.md +11 -63
- package/.agent-src/rules/think-before-action.md +22 -87
- package/.agent-src/rules/token-efficiency.md +10 -74
- package/.agent-src/rules/token-optimizer-maintenance.md +68 -0
- package/.agent-src/rules/tool-safety.md +4 -0
- package/.agent-src/rules/ui-audit-gate.md +25 -61
- package/.agent-src/rules/upstream-proposal.md +9 -67
- package/.agent-src/rules/user-interaction.md +22 -108
- package/.agent-src/rules/verify-before-complete.md +1 -1
- package/.agent-src/skills/adversarial-review/SKILL.md +1 -0
- package/.agent-src/skills/agent-docs-writing/SKILL.md +1 -1
- package/.agent-src/skills/ai-council/SKILL.md +197 -8
- package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/.agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/.agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/.agent-src/skills/authz-review/SKILL.md +1 -1
- package/.agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/.agent-src/skills/blast-radius-analyzer/SKILL.md +8 -8
- package/.agent-src/skills/bug-analyzer/SKILL.md +6 -5
- package/.agent-src/skills/code-refactoring/SKILL.md +4 -4
- package/.agent-src/skills/code-review/SKILL.md +2 -2
- package/.agent-src/skills/command-writing/SKILL.md +11 -0
- package/.agent-src/skills/composer-packages/SKILL.md +2 -2
- package/.agent-src/skills/context-authoring/SKILL.md +11 -0
- package/.agent-src/skills/context-document/SKILL.md +1 -1
- package/.agent-src/skills/copilot-agents-optimization/SKILL.md +23 -0
- package/.agent-src/skills/copilot-config/SKILL.md +1 -1
- package/.agent-src/skills/dependency-upgrade/SKILL.md +2 -2
- package/.agent-src/skills/devcontainer/SKILL.md +2 -2
- package/.agent-src/skills/developer-like-execution/SKILL.md +1 -1
- package/.agent-src/skills/docker/SKILL.md +1 -1
- package/.agent-src/skills/dto-creator/SKILL.md +1 -1
- package/.agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/.agent-src/skills/fe-design/SKILL.md +4 -4
- package/.agent-src/skills/feature-planning/SKILL.md +5 -5
- package/.agent-src/skills/funnel-analysis/SKILL.md +1 -1
- package/.agent-src/skills/laravel/SKILL.md +1 -1
- package/.agent-src/skills/laravel-notifications/SKILL.md +5 -5
- package/.agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/.agent-src/skills/laravel-pulse/SKILL.md +4 -4
- package/.agent-src/skills/laravel-reverb/SKILL.md +2 -2
- package/.agent-src/skills/laravel-scheduling/SKILL.md +1 -1
- package/.agent-src/skills/migration-creator/SKILL.md +7 -7
- package/.agent-src/skills/multi-tenancy/SKILL.md +8 -8
- package/.agent-src/skills/performance-analysis/SKILL.md +3 -3
- package/.agent-src/skills/pest-testing/SKILL.md +6 -6
- package/.agent-src/skills/php-service/SKILL.md +2 -2
- package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/.agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/.agent-src/skills/project-analyzer/SKILL.md +4 -4
- package/.agent-src/skills/prompt-optimizer/SKILL.md +108 -0
- package/.agent-src/skills/readme-reviewer/SKILL.md +1 -1
- package/.agent-src/skills/roadmap-management/SKILL.md +7 -7
- package/.agent-src/skills/rule-writing/SKILL.md +33 -0
- package/.agent-src/skills/sentry-integration/SKILL.md +1 -1
- package/.agent-src/skills/skill-writing/SKILL.md +14 -0
- package/.agent-src/skills/systematic-debugging/SKILL.md +22 -2
- package/.agent-src/skills/technical-specification/SKILL.md +58 -1
- package/.agent-src/skills/terraform/SKILL.md +2 -2
- package/.agent-src/skills/terragrunt/SKILL.md +8 -8
- package/.agent-src/skills/test-performance/SKILL.md +5 -5
- package/.agent-src/skills/threat-modeling/SKILL.md +3 -2
- package/.agent-src/skills/token-optimizer/SKILL.md +110 -0
- package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/.agent-src/templates/AGENTS.md +1 -1
- package/.agent-src/templates/agent-settings.md +35 -19
- package/.agent-src/templates/command.md +17 -1
- package/.agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/.agent-src/templates/contexts.md +1 -1
- package/.agent-src/templates/copilot-instructions.md +21 -0
- package/.agent-src/templates/copilot-review-instructions.md +76 -0
- package/.agent-src/templates/features.md +1 -1
- package/.agent-src/templates/roadmaps.md +10 -2
- package/.agent-src/templates/rule.md +129 -0
- package/.agent-src/templates/skill.md +17 -0
- package/.claude-plugin/marketplace.json +12 -2
- package/AGENTS.md +32 -5
- package/CHANGELOG.md +107 -3
- package/README.md +22 -21
- package/config/agent-settings.template.yml +66 -10
- package/config/gitignore-block.txt +7 -0
- package/docs/architecture.md +86 -5
- package/docs/catalog.md +16 -6
- package/docs/contracts/agent-memory-contract.md +1 -1
- package/docs/contracts/command-clusters.md +45 -1
- package/docs/contracts/context-paths.md +2 -1
- package/docs/contracts/file-ownership-matrix.json +354 -500
- package/docs/contracts/iron-law-overrides.txt +25 -0
- package/docs/contracts/kernel-membership.md +273 -0
- package/docs/contracts/load-context-schema.md +26 -11
- package/docs/contracts/pilot/agent-authority.md +24 -0
- package/docs/contracts/pilot/direct-answers.md +70 -0
- package/docs/contracts/pilot/language-and-tone.md +63 -0
- package/docs/contracts/rule-classification.md +170 -0
- package/docs/contracts/rule-router.md +153 -0
- package/docs/customization.md +17 -6
- package/docs/decisions/ADR-001-kernel-swap-deferred.md +109 -0
- package/docs/decisions/ADR-002-kernel-bucket-overrides.md +124 -0
- package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +126 -0
- package/docs/decisions/ADR-rule-kernel-and-router.md +122 -0
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +176 -0
- package/docs/guidelines/agent-infra/rule-type-governance.md +73 -0
- package/docs/guidelines/agent-infra/size-and-scope.md +13 -2
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +119 -0
- package/docs/guidelines/augment-portability-patterns.md +68 -0
- package/docs/guidelines/php/php-coding-patterns.md +62 -0
- package/package.json +1 -1
- package/scripts/_p43_bodies.py +235 -0
- package/scripts/_p43_compress.py +118 -0
- package/scripts/_p4_migrate.py +199 -0
- package/scripts/_phase2_shim_helper.py +1 -1
- package/scripts/_pilot_council_question.py +57 -0
- package/scripts/_pilot_measure.py +53 -0
- package/scripts/ai_council/session.py +107 -5
- package/scripts/build_linear_digest.py +3 -5
- package/scripts/check_always_budget.py +39 -6
- package/scripts/check_compressed_paths.py +213 -0
- package/scripts/check_compression.py +15 -0
- package/scripts/check_context_paths.py +1 -0
- package/scripts/check_council_layout.py +105 -0
- package/scripts/check_council_references.py +145 -0
- package/scripts/check_portability.py +2 -0
- package/scripts/check_references.py +2 -0
- package/scripts/check_token_optimizer_freshness.py +131 -0
- package/scripts/compile_router.py +148 -0
- package/scripts/compress.py +219 -11
- package/scripts/council_cli.py +132 -11
- package/scripts/council_prune.py +81 -0
- package/scripts/count_token_optimizer_usage.sh +54 -0
- package/scripts/install.sh +44 -2
- package/scripts/iron_law_sha.py +98 -0
- package/scripts/lint_load_context.py +35 -5
- package/scripts/measure_rule_budget.py +314 -0
- package/scripts/migrate_command_suggestions.py +2 -2
- package/scripts/prototype_lint_contradictions.py +150 -0
- package/scripts/schemas/command.schema.json +5 -0
- package/scripts/schemas/rule.schema.json +60 -6
- package/scripts/schemas/skill.schema.json +5 -0
- package/scripts/skill_linter.py +197 -7
- package/scripts/smoke_path_resolution.py +93 -0
- package/scripts/validate_frontmatter.py +41 -1
- package/.agent-src/commands/roadmap/execute.md +0 -109
- package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +0 -72
- package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +0 -79
- package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +0 -87
- package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +0 -62
- package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +0 -85
- package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +0 -65
- package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +0 -53
- /package/{docs → .agent-src/contexts}/contracts/artifact-engagement-flow.md +0 -0
- /package/{docs → .agent-src/contexts}/contracts/command-suggestion-flow.md +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Compile rule frontmatter into ``router.json``.
|
|
3
|
+
|
|
4
|
+
Reads ``.agent-src.uncompressed/rules/*.md``; produces deterministic JSON
|
|
5
|
+
mapping kernel + tier-1 + tier-2 rules to their triggers and routed
|
|
6
|
+
artifacts, per ``docs/contracts/rule-router.md``.
|
|
7
|
+
|
|
8
|
+
Stdlib-only, deterministic (sorted keys + sorted lists), idempotent.
|
|
9
|
+
Wired into ``task generate-tools`` after the compress step.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
18
|
+
RULES_DIR = ROOT / ".agent-src.uncompressed" / "rules"
|
|
19
|
+
OUT_PATH = ROOT / "router.json"
|
|
20
|
+
SCHEMA_VERSION = 1
|
|
21
|
+
|
|
22
|
+
# Maps legacy tier values to the router-canonical names. See
|
|
23
|
+
# docs/contracts/rule-router.md § Backward compatibility.
|
|
24
|
+
LEGACY_TIER_MAP = {
|
|
25
|
+
"1": "tier-1",
|
|
26
|
+
"2": "tier-2",
|
|
27
|
+
"2a": "tier-2",
|
|
28
|
+
"3": "tier-1",
|
|
29
|
+
"mechanical-already": "tier-1",
|
|
30
|
+
"kernel": "kernel",
|
|
31
|
+
"tier-1": "tier-1",
|
|
32
|
+
"tier-2": "tier-2",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
ALLOWED_TIERS = {"kernel", "tier-1", "tier-2"}
|
|
36
|
+
ALLOWED_PROFILES = {"minimal", "balanced", "full"}
|
|
37
|
+
ALLOWED_TRIGGER_KEYS = {"keyword", "phrase", "intent", "file_pattern",
|
|
38
|
+
"path_prefix", "command"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _parse_frontmatter(text: str) -> dict:
|
|
42
|
+
if not text.startswith("---\n"):
|
|
43
|
+
return {}
|
|
44
|
+
end = text.find("\n---", 4)
|
|
45
|
+
if end < 0:
|
|
46
|
+
return {}
|
|
47
|
+
block = text[4:end]
|
|
48
|
+
try:
|
|
49
|
+
import yaml # type: ignore
|
|
50
|
+
data = yaml.safe_load(block) or {}
|
|
51
|
+
return data if isinstance(data, dict) else {}
|
|
52
|
+
except ImportError:
|
|
53
|
+
return _parse_frontmatter_minimal(block)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _parse_frontmatter_minimal(block: str) -> dict:
|
|
57
|
+
"""Minimal YAML parser fallback (flat scalars + simple lists)."""
|
|
58
|
+
out: dict = {}
|
|
59
|
+
cur_key = None
|
|
60
|
+
for raw in block.splitlines():
|
|
61
|
+
line = raw.rstrip()
|
|
62
|
+
if not line or line.lstrip().startswith("#"):
|
|
63
|
+
continue
|
|
64
|
+
if line.startswith(" - ") and cur_key:
|
|
65
|
+
out.setdefault(cur_key, []).append(line[4:].strip())
|
|
66
|
+
elif ":" in line and not line.startswith(" "):
|
|
67
|
+
k, _, v = line.partition(":")
|
|
68
|
+
cur_key = k.strip()
|
|
69
|
+
v = v.strip()
|
|
70
|
+
if v in ("", "[]"):
|
|
71
|
+
out[cur_key] = [] if v == "[]" else None
|
|
72
|
+
else:
|
|
73
|
+
out[cur_key] = v.strip('"').strip("'")
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _resolve_tier(rule_type: str, raw_tier: str) -> str:
|
|
78
|
+
if rule_type == "always":
|
|
79
|
+
return "kernel"
|
|
80
|
+
return LEGACY_TIER_MAP.get(str(raw_tier), "tier-2")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _normalize_trigger(item) -> dict | None:
|
|
84
|
+
if not isinstance(item, dict):
|
|
85
|
+
return None
|
|
86
|
+
keys = [k for k in item if k in ALLOWED_TRIGGER_KEYS]
|
|
87
|
+
if len(keys) != 1:
|
|
88
|
+
return None
|
|
89
|
+
return {keys[0]: str(item[keys[0]])}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _collect(rules_dir: Path) -> dict:
|
|
93
|
+
kernel: list[str] = []
|
|
94
|
+
tiered: dict[str, list[dict]] = {"tier-1": [], "tier-2": []}
|
|
95
|
+
for path in sorted(rules_dir.glob("*.md")):
|
|
96
|
+
fm = _parse_frontmatter(path.read_text(encoding="utf-8"))
|
|
97
|
+
if not fm:
|
|
98
|
+
continue
|
|
99
|
+
rule_id = path.stem
|
|
100
|
+
rule_type = str(fm.get("type", "auto"))
|
|
101
|
+
tier = _resolve_tier(rule_type, fm.get("tier", ""))
|
|
102
|
+
if tier not in ALLOWED_TIERS:
|
|
103
|
+
continue
|
|
104
|
+
if tier == "kernel":
|
|
105
|
+
kernel.append(rule_id)
|
|
106
|
+
continue
|
|
107
|
+
triggers_raw = fm.get("triggers") or []
|
|
108
|
+
triggers = [t for t in (_normalize_trigger(x) for x in triggers_raw) if t]
|
|
109
|
+
routes_to = sorted(str(x) for x in (fm.get("routes_to") or []))
|
|
110
|
+
entry = {"id": rule_id, "triggers": triggers, "routes_to": routes_to}
|
|
111
|
+
tiered[tier].append(entry)
|
|
112
|
+
for k in tiered:
|
|
113
|
+
tiered[k].sort(key=lambda x: x["id"])
|
|
114
|
+
return {"kernel": sorted(kernel), **{k.replace("-", "_"): v for k, v in tiered.items()}}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def build() -> dict:
|
|
118
|
+
collected = _collect(RULES_DIR)
|
|
119
|
+
return {
|
|
120
|
+
"schema_version": SCHEMA_VERSION,
|
|
121
|
+
"kernel": collected["kernel"],
|
|
122
|
+
"tier_1": collected["tier_1"],
|
|
123
|
+
"tier_2": collected["tier_2"],
|
|
124
|
+
"profiles": {
|
|
125
|
+
"minimal": ["__kernel__"],
|
|
126
|
+
"balanced": ["__kernel__", "__tier_1__"],
|
|
127
|
+
"full": ["__kernel__", "__tier_1__", "__tier_2__"],
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main(argv: list[str]) -> int:
|
|
133
|
+
out = build()
|
|
134
|
+
text = json.dumps(out, indent=2, sort_keys=False) + "\n"
|
|
135
|
+
if "--check" in argv:
|
|
136
|
+
if not OUT_PATH.exists() or OUT_PATH.read_text(encoding="utf-8") != text:
|
|
137
|
+
print("router.json out of date — run scripts/compile_router.py", file=sys.stderr)
|
|
138
|
+
return 1
|
|
139
|
+
print("✅ router.json is up to date")
|
|
140
|
+
return 0
|
|
141
|
+
OUT_PATH.write_text(text, encoding="utf-8")
|
|
142
|
+
counts = (len(out["kernel"]), len(out["tier_1"]), len(out["tier_2"]))
|
|
143
|
+
print(f"✅ router.json — kernel={counts[0]} tier-1={counts[1]} tier-2={counts[2]}")
|
|
144
|
+
return 0
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
sys.exit(main(sys.argv[1:]))
|
package/scripts/compress.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
3
|
Agent-config sync — compress .agent-src.uncompressed/ → .agent-src/
|
|
4
|
-
and project .agent-src/ → .augment/ (copies for rules
|
|
4
|
+
and project .agent-src/ → .augment/ (copies for rules by default,
|
|
5
|
+
symlinks for the rest; opt into rule symlinks via
|
|
6
|
+
augment.rules_use_symlinks in .agent-settings.yml).
|
|
5
7
|
|
|
6
8
|
Copies non-.md files as-is. Lists .md files that need compression (done by the
|
|
7
9
|
Augment agent interactively). Tracks SHA-256 hashes of source files to detect
|
|
@@ -19,6 +21,7 @@ Usage:
|
|
|
19
21
|
|
|
20
22
|
import hashlib
|
|
21
23
|
import json
|
|
24
|
+
import re
|
|
22
25
|
import shutil
|
|
23
26
|
import sys
|
|
24
27
|
from pathlib import Path
|
|
@@ -28,11 +31,41 @@ SOURCE_DIR = PROJECT_ROOT / ".agent-src.uncompressed"
|
|
|
28
31
|
TARGET_DIR = PROJECT_ROOT / ".agent-src"
|
|
29
32
|
AUGMENT_DIR = PROJECT_ROOT / ".augment"
|
|
30
33
|
HASH_FILE = PROJECT_ROOT / ".compression-hashes.json"
|
|
34
|
+
SETTINGS_FILE = PROJECT_ROOT / ".agent-settings.yml"
|
|
31
35
|
|
|
32
36
|
# Files to copy as-is even if .md (not compressed by agent)
|
|
33
37
|
COPY_AS_IS = {"README.md"}
|
|
34
38
|
|
|
35
39
|
|
|
40
|
+
def _read_augment_rules_use_symlinks() -> bool:
|
|
41
|
+
"""Read augment.rules_use_symlinks from .agent-settings.yml.
|
|
42
|
+
|
|
43
|
+
Returns True only when the setting is present under the top-level
|
|
44
|
+
``augment:`` block and resolves to a truthy YAML scalar
|
|
45
|
+
(true/yes/on/1, case-insensitive). Missing file, missing block, or
|
|
46
|
+
any other value → False (preserve copy default).
|
|
47
|
+
"""
|
|
48
|
+
if not SETTINGS_FILE.exists():
|
|
49
|
+
return False
|
|
50
|
+
try:
|
|
51
|
+
text = SETTINGS_FILE.read_text(encoding="utf-8")
|
|
52
|
+
except OSError:
|
|
53
|
+
return False
|
|
54
|
+
in_augment = False
|
|
55
|
+
for line in text.splitlines():
|
|
56
|
+
stripped = line.lstrip()
|
|
57
|
+
if not stripped or stripped.startswith("#"):
|
|
58
|
+
continue
|
|
59
|
+
if not line.startswith((" ", "\t")):
|
|
60
|
+
in_augment = stripped.startswith("augment:")
|
|
61
|
+
continue
|
|
62
|
+
if in_augment:
|
|
63
|
+
m = re.match(r"^\s+rules_use_symlinks\s*:\s*([^\s#]+)", line)
|
|
64
|
+
if m:
|
|
65
|
+
return m.group(1).strip().lower() in ("true", "yes", "on", "1")
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
36
69
|
|
|
37
70
|
|
|
38
71
|
def file_hash(filepath: Path) -> str:
|
|
@@ -59,17 +92,42 @@ def save_hashes(hashes: dict) -> None:
|
|
|
59
92
|
|
|
60
93
|
|
|
61
94
|
def mark_done(relative_path: str) -> None:
|
|
62
|
-
"""Mark a single file as compressed by storing its current source hash.
|
|
95
|
+
"""Mark a single file as compressed by storing its current source hash.
|
|
96
|
+
|
|
97
|
+
Also runs the path rewriter on the just-written `.agent-src/<path>` so
|
|
98
|
+
logical names from the source frontmatter resolve to deployment-correct
|
|
99
|
+
relative paths in the shipped layer (P1 of road-to-path-fixes.md).
|
|
100
|
+
Idempotent — re-running is a no-op.
|
|
101
|
+
"""
|
|
63
102
|
source_file = SOURCE_DIR / relative_path
|
|
64
103
|
if not source_file.exists():
|
|
65
104
|
print(f"❌ Source file not found: {relative_path}")
|
|
66
105
|
sys.exit(1)
|
|
106
|
+
apply_path_rewriter(relative_path)
|
|
67
107
|
hashes = load_hashes()
|
|
68
108
|
hashes[relative_path] = file_hash(source_file)
|
|
69
109
|
save_hashes(hashes)
|
|
70
110
|
print(f"✅ Marked as compressed: {relative_path}")
|
|
71
111
|
|
|
72
112
|
|
|
113
|
+
def apply_path_rewriter(relative_path: str) -> bool:
|
|
114
|
+
"""Apply `_rewrite_paths` to `.agent-src/<relative_path>` in-place.
|
|
115
|
+
|
|
116
|
+
Returns True if the file was modified, False otherwise. Silently
|
|
117
|
+
returns False if the target doesn't exist (compression hasn't run
|
|
118
|
+
yet) — `--mark-done` is also valid before content exists.
|
|
119
|
+
"""
|
|
120
|
+
target = TARGET_DIR / relative_path
|
|
121
|
+
if not target.exists() or not relative_path.endswith(".md"):
|
|
122
|
+
return False
|
|
123
|
+
original = target.read_text(encoding="utf-8")
|
|
124
|
+
rewritten = _rewrite_paths(original, relative_path)
|
|
125
|
+
if rewritten == original:
|
|
126
|
+
return False
|
|
127
|
+
target.write_text(rewritten, encoding="utf-8")
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
|
|
73
131
|
def mark_all_done() -> None:
|
|
74
132
|
"""Mark ALL .md files as compressed (e.g. after initial full compression)."""
|
|
75
133
|
hashes = load_hashes()
|
|
@@ -250,6 +308,144 @@ def strip_frontmatter(content: str) -> str:
|
|
|
250
308
|
return content
|
|
251
309
|
|
|
252
310
|
|
|
311
|
+
# ── Path rewriter (P1 of road-to-path-fixes.md) ───────────────────────────
|
|
312
|
+
# Source files use logical names that the rewriter resolves at compress
|
|
313
|
+
# time, so the shipped `.agent-src/` (and `.augment/` projection) carry
|
|
314
|
+
# deployment-correct relative paths without the agent author having to
|
|
315
|
+
# know how deep their file lives.
|
|
316
|
+
#
|
|
317
|
+
# Frontmatter rewrites:
|
|
318
|
+
# load_context: / load_context_eager:
|
|
319
|
+
# contexts/<area>/<file>.md (logical, preferred)
|
|
320
|
+
# .agent-src.uncompressed/contexts/<area>/<file>.md (legacy)
|
|
321
|
+
# → ../contexts/<area>/<file>.md (relative from .agent-src/rules/)
|
|
322
|
+
# triggers[].path_prefix:
|
|
323
|
+
# LEFT ALONE — `path_prefix:` is a literal match pattern, not a
|
|
324
|
+
# file reference. Source-of-truth rules that fire on edits under
|
|
325
|
+
# `.agent-src.uncompressed/` keep that prefix verbatim (see
|
|
326
|
+
# road-to-path-fixes.md P2.2 / Modified Option 1).
|
|
327
|
+
#
|
|
328
|
+
# Body-link rewrites:
|
|
329
|
+
# ../../docs/guidelines/<file>.md → ../docs/guidelines/<file>.md
|
|
330
|
+
# ../../docs/contracts/<file>.md → ../docs/contracts/<file>.md
|
|
331
|
+
#
|
|
332
|
+
# Idempotent: applying twice is a no-op (rewritten patterns no longer
|
|
333
|
+
# match the source patterns).
|
|
334
|
+
|
|
335
|
+
_LEGACY_SRC_PREFIX = ".agent-src.uncompressed/"
|
|
336
|
+
_PROJECTED_SRC_PREFIX = ".agent-src/"
|
|
337
|
+
|
|
338
|
+
# A YAML list item under load_context*: ` - some/path.md` (optionally quoted)
|
|
339
|
+
_FM_LIST_ITEM_RE = re.compile(r'^(\s*-\s*)(["\']?)([^"\'\n]+?\.md)(["\']?)\s*$')
|
|
340
|
+
|
|
341
|
+
# `path_prefix:` line — top-level or under `triggers:` (with leading dash)
|
|
342
|
+
_FM_PATH_PREFIX_RE = re.compile(
|
|
343
|
+
r'^(\s*(?:-\s+)?path_prefix:\s*)(["\']?)([^"\'\n]+?)(["\']?)\s*$'
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
# Body-link patterns (relative two-up to docs/) — capture the docs/... tail
|
|
347
|
+
_BODY_DOCS_RE = re.compile(r'\.\./\.\./(docs/(?:guidelines|contracts)/[^)\s]+\.md)')
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _depth_prefix(source_relative_path: str) -> str:
|
|
351
|
+
"""Return the `../` chain to climb from `<source_relative_path>` back to
|
|
352
|
+
the source root. A file at `rules/X.md` (1 dir deep) needs `../`; a
|
|
353
|
+
file at `commands/council/default.md` (2 dirs deep) needs `../../`.
|
|
354
|
+
"""
|
|
355
|
+
parts = Path(source_relative_path).parts
|
|
356
|
+
depth = max(len(parts) - 1, 1)
|
|
357
|
+
return "../" * depth
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _split_frontmatter(content: str):
|
|
361
|
+
"""Return (frontmatter_lines, body) — frontmatter_lines is None if no FM."""
|
|
362
|
+
if not content.startswith("---\n"):
|
|
363
|
+
return None, content
|
|
364
|
+
end = content.find("\n---\n", 4)
|
|
365
|
+
if end == -1:
|
|
366
|
+
return None, content
|
|
367
|
+
fm_text = content[4:end]
|
|
368
|
+
body = content[end + len("\n---\n"):]
|
|
369
|
+
return fm_text.split("\n"), body
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _rewrite_load_context_value(value: str, prefix: str) -> str:
|
|
373
|
+
"""Rewrite a single `load_context` list-item value to a deployment path."""
|
|
374
|
+
# Already relative or absolute → leave alone (idempotence).
|
|
375
|
+
if value.startswith(("../", "./", "/")):
|
|
376
|
+
return value
|
|
377
|
+
# Legacy fully-qualified source prefix.
|
|
378
|
+
if value.startswith(_LEGACY_SRC_PREFIX):
|
|
379
|
+
return prefix + value[len(_LEGACY_SRC_PREFIX):]
|
|
380
|
+
# Projected source prefix (defensive — also strip).
|
|
381
|
+
if value.startswith(_PROJECTED_SRC_PREFIX):
|
|
382
|
+
return prefix + value[len(_PROJECTED_SRC_PREFIX):]
|
|
383
|
+
# Logical name (e.g. `contexts/execution/foo.md`).
|
|
384
|
+
return prefix + value
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _rewrite_path_prefix_value(value: str) -> str:
|
|
388
|
+
"""No-op for `triggers[].path_prefix:` values.
|
|
389
|
+
|
|
390
|
+
`path_prefix:` is a literal match pattern the host evaluates against
|
|
391
|
+
the file the agent is editing — not a file reference. Rewriting it
|
|
392
|
+
breaks the workflow it was authored for: source-of-truth rules that
|
|
393
|
+
fire when the agent edits files under `.agent-src.uncompressed/`
|
|
394
|
+
keep that prefix verbatim. The prefix ban therefore applies only to
|
|
395
|
+
`load_context:` entries and body links (see road-to-path-fixes.md
|
|
396
|
+
P2.2 + the AI-Council convergence on 2026-05-06).
|
|
397
|
+
"""
|
|
398
|
+
return value
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _rewrite_frontmatter_lines(lines, prefix):
|
|
402
|
+
"""Apply load_context / path_prefix rewrites to a frontmatter line list."""
|
|
403
|
+
in_load_context = False
|
|
404
|
+
out = []
|
|
405
|
+
for line in lines:
|
|
406
|
+
bare = line.lstrip()
|
|
407
|
+
if bare.startswith(("load_context:", "load_context_eager:")):
|
|
408
|
+
in_load_context = True
|
|
409
|
+
out.append(line)
|
|
410
|
+
continue
|
|
411
|
+
if in_load_context:
|
|
412
|
+
m = _FM_LIST_ITEM_RE.match(line)
|
|
413
|
+
if m:
|
|
414
|
+
indent, q1, value, q2 = m.groups()
|
|
415
|
+
rewritten = _rewrite_load_context_value(value, prefix)
|
|
416
|
+
out.append(f"{indent}{q1}{rewritten}{q2}")
|
|
417
|
+
continue
|
|
418
|
+
in_load_context = False
|
|
419
|
+
# fall through to path_prefix / passthrough
|
|
420
|
+
m = _FM_PATH_PREFIX_RE.match(line)
|
|
421
|
+
if m:
|
|
422
|
+
head, q1, value, q2 = m.groups()
|
|
423
|
+
out.append(f"{head}{q1}{_rewrite_path_prefix_value(value)}{q2}")
|
|
424
|
+
continue
|
|
425
|
+
out.append(line)
|
|
426
|
+
return out
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def _rewrite_body_links(body: str, prefix: str) -> str:
|
|
430
|
+
"""Rewrite `../../docs/{guidelines,contracts}/...` to use depth-prefix."""
|
|
431
|
+
return _BODY_DOCS_RE.sub(prefix + r"\1", body)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _rewrite_paths(content: str, source_relative_path: str) -> str:
|
|
435
|
+
"""Rewrite logical / legacy paths in `content` for a file shipped at
|
|
436
|
+
`.agent-src/{source_relative_path}`. Idempotent.
|
|
437
|
+
|
|
438
|
+
See module-level comment above for the full pattern catalog.
|
|
439
|
+
"""
|
|
440
|
+
prefix = _depth_prefix(source_relative_path)
|
|
441
|
+
fm_lines, body = _split_frontmatter(content)
|
|
442
|
+
body = _rewrite_body_links(body, prefix)
|
|
443
|
+
if fm_lines is None:
|
|
444
|
+
return body
|
|
445
|
+
new_fm = _rewrite_frontmatter_lines(fm_lines, prefix)
|
|
446
|
+
return "---\n" + "\n".join(new_fm) + "\n---\n" + body
|
|
447
|
+
|
|
448
|
+
|
|
253
449
|
def generate_rule_symlinks() -> int:
|
|
254
450
|
"""Create symlink directories for rules (.claude/rules/, .cursor/rules/, .clinerules/).
|
|
255
451
|
|
|
@@ -499,8 +695,10 @@ def generate_tools() -> None:
|
|
|
499
695
|
# ── .augment/ projection ──────────────────────────────────────────────
|
|
500
696
|
# The package uses .agent-src/ as the tool-agnostic compressed source of truth.
|
|
501
697
|
# .augment/ is a generated projection so that Augment Code (which reads from
|
|
502
|
-
# .augment/
|
|
503
|
-
#
|
|
698
|
+
# .augment/) works on the package repo itself. Rules default to copies
|
|
699
|
+
# because Augment Code historically does not load symlinked rule files;
|
|
700
|
+
# flip augment.rules_use_symlinks: true in .agent-settings.yml to switch
|
|
701
|
+
# them to symlinks (everything else is always symlinked).
|
|
504
702
|
|
|
505
703
|
# Subdirectories of .agent-src/ that map into .augment/ as symlinks.
|
|
506
704
|
AUGMENT_SYMLINK_DIRS = ("skills", "commands", "guidelines", "personas", "templates", "contexts", "scripts")
|
|
@@ -509,34 +707,44 @@ AUGMENT_SYMLINK_FILES = ("README.md",)
|
|
|
509
707
|
|
|
510
708
|
|
|
511
709
|
def project_to_augment() -> None:
|
|
512
|
-
"""Mirror .agent-src/ into .augment/.
|
|
710
|
+
"""Mirror .agent-src/ into .augment/. Symlink everything except rules,
|
|
711
|
+
which default to copies; opt into rule symlinks via
|
|
712
|
+
augment.rules_use_symlinks in .agent-settings.yml."""
|
|
513
713
|
if not TARGET_DIR.exists():
|
|
514
714
|
print(f" ⚠️ {TARGET_DIR.name}/ not found — nothing to project")
|
|
515
715
|
return
|
|
516
716
|
|
|
517
717
|
AUGMENT_DIR.mkdir(parents=True, exist_ok=True)
|
|
518
718
|
|
|
519
|
-
|
|
719
|
+
use_symlinks = _read_augment_rules_use_symlinks()
|
|
720
|
+
|
|
721
|
+
# Rules: copy by default (Augment Code historically does not load
|
|
722
|
+
# symlinked rules), or symlink when augment.rules_use_symlinks is true.
|
|
520
723
|
src_rules = TARGET_DIR / "rules"
|
|
521
724
|
dst_rules = AUGMENT_DIR / "rules"
|
|
522
725
|
dst_rules.mkdir(parents=True, exist_ok=True)
|
|
523
726
|
existing = {f.name for f in dst_rules.iterdir() if f.is_file() or f.is_symlink()}
|
|
524
727
|
current = set()
|
|
525
|
-
|
|
728
|
+
written = 0
|
|
526
729
|
if src_rules.exists():
|
|
527
730
|
for rule in sorted(src_rules.glob("*.md")):
|
|
528
731
|
target = dst_rules / rule.name
|
|
529
|
-
|
|
732
|
+
# Always remove first to avoid copy↔symlink mode mismatch.
|
|
733
|
+
if target.is_symlink() or target.exists():
|
|
530
734
|
target.unlink()
|
|
531
|
-
|
|
735
|
+
if use_symlinks:
|
|
736
|
+
target.symlink_to(Path("..") / ".." / ".agent-src" / "rules" / rule.name)
|
|
737
|
+
else:
|
|
738
|
+
shutil.copy2(rule, target)
|
|
532
739
|
current.add(rule.name)
|
|
533
|
-
|
|
740
|
+
written += 1
|
|
534
741
|
# Remove stale rule files
|
|
535
742
|
removed_rules = 0
|
|
536
743
|
for name in existing - current:
|
|
537
744
|
(dst_rules / name).unlink()
|
|
538
745
|
removed_rules += 1
|
|
539
|
-
|
|
746
|
+
mode_label = "Symlinked" if use_symlinks else "Copied"
|
|
747
|
+
print(f" ✅ {mode_label} {written} rules to .augment/rules/" + (f" ({removed_rules} stale removed)" if removed_rules else ""))
|
|
540
748
|
|
|
541
749
|
# Subdirectories: replace each with a symlink → ../.agent-src/<subdir>
|
|
542
750
|
for sub in AUGMENT_SYMLINK_DIRS:
|