@event4u/agent-config 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/council/analysis.md +142 -0
- package/.agent-src/commands/council/debate.md +129 -0
- package/.agent-src/commands/council/default.md +8 -0
- package/.agent-src/commands/council/design.md +16 -12
- package/.agent-src/commands/council/optimize.md +16 -15
- package/.agent-src/commands/council/pr.md +12 -12
- package/.agent-src/commands/council.md +48 -2
- package/.agent-src/commands/memory/learn-low-impact.md +143 -0
- package/.agent-src/personas/advisors/contrarian.md +95 -0
- package/.agent-src/personas/advisors/executor.md +99 -0
- package/.agent-src/personas/advisors/expansionist.md +98 -0
- package/.agent-src/personas/advisors/first-principles.md +98 -0
- package/.agent-src/personas/advisors/outsider.md +102 -0
- package/.agent-src/rules/ask-when-uncertain.md +10 -6
- package/.agent-src/rules/copilot-routing.md +19 -0
- package/.agent-src/rules/devcontainer-routing.md +20 -0
- package/.agent-src/rules/external-reference-deep-dive.md +1 -1
- package/.agent-src/rules/fast-path-marker-visibility.md +38 -0
- package/.agent-src/rules/laravel-routing.md +20 -0
- package/.agent-src/rules/low-impact-corpus-privacy-floor.md +74 -0
- package/.agent-src/rules/symfony-routing.md +20 -0
- package/.agent-src/skills/ai-council/SKILL.md +388 -10
- package/.agent-src/skills/copilot-config/SKILL.md +1 -1
- package/.agent-src/skills/devcontainer/SKILL.md +1 -1
- package/.agent-src/skills/laravel/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-core/SKILL.md +1 -1
- package/.agent-src/skills/project-analyzer/SKILL.md +1 -1
- package/.agent-src/skills/symfony-workflow/SKILL.md +1 -1
- package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/.claude-plugin/marketplace.json +4 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +346 -124
- package/CONTRIBUTING.md +5 -0
- package/README.md +6 -6
- package/config/agent-settings.template.yml +5 -93
- package/config/gitignore-block.txt +6 -0
- package/docs/architecture/multi-tool-projection.md +53 -0
- package/docs/architecture/{compression.md → source-projection.md} +21 -3
- package/docs/architecture.md +15 -15
- package/docs/archive/CHANGELOG-pre-2.11.0.md +141 -0
- package/docs/catalog.md +25 -12
- package/docs/contracts/adr-architectural-consensus-mechanism.md +68 -0
- package/docs/contracts/adr-level-6-productization.md +7 -9
- package/docs/contracts/ai-council-config.md +658 -0
- package/docs/contracts/command-clusters.md +58 -2
- package/docs/contracts/command-surface-tiers.md +3 -2
- package/docs/contracts/cost-profile-defaults.md +5 -0
- package/docs/contracts/decision-engine-gates.md +5 -0
- package/docs/contracts/decision-trace-v1.md +2 -2
- package/docs/contracts/file-ownership-matrix.json +1735 -72
- package/docs/contracts/installed-tools-lockfile.md +2 -1
- package/docs/contracts/low-impact-corpus-format.md +95 -0
- package/docs/contracts/mcp-beta-criteria.md +6 -5
- package/docs/contracts/mcp-cloud-scope.md +5 -4
- package/docs/contracts/multi-tool-projection-fidelity.md +115 -0
- package/docs/contracts/release-trunk-sync.md +4 -3
- package/docs/contracts/tier-3-contrib-plugin.md +5 -6
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/installed-tools-manifest.md +2 -1
- package/docs/installation.md +32 -0
- package/package.json +1 -1
- package/scripts/_archive/README.md +59 -0
- package/scripts/_cli/cmd_doctor.py +134 -0
- package/scripts/ai_council/_default_prices.py +10 -1
- package/scripts/ai_council/advisors.py +148 -0
- package/scripts/ai_council/airgap.py +165 -0
- package/scripts/ai_council/cli_hints.py +123 -0
- package/scripts/ai_council/clients.py +959 -5
- package/scripts/ai_council/compile_corpus.py +178 -0
- package/scripts/ai_council/confidence_gate.py +156 -0
- package/scripts/ai_council/config.py +1364 -0
- package/scripts/ai_council/consensus.py +329 -0
- package/scripts/ai_council/events_log.py +137 -0
- package/scripts/ai_council/learn_low_impact_preview.py +252 -0
- package/scripts/ai_council/low_impact.py +714 -0
- package/scripts/ai_council/low_impact_corpus.py +466 -0
- package/scripts/ai_council/low_impact_intake.py +163 -0
- package/scripts/ai_council/modes.py +6 -1
- package/scripts/ai_council/necessity.py +782 -0
- package/scripts/ai_council/orchestrator.py +872 -20
- package/scripts/ai_council/probation_gate.py +152 -0
- package/scripts/ai_council/prompts.py +335 -0
- package/scripts/ai_council/redact_low_impact_entry.py +155 -0
- package/scripts/ai_council/replay.py +155 -0
- package/scripts/ai_council/session.py +19 -1
- package/scripts/ai_council/shadow_dispatch.py +235 -0
- package/scripts/ai_council/solo_dispatch.py +226 -0
- package/scripts/audit_cloud_compatibility.py +74 -0
- package/scripts/audit_command_surface.py +363 -0
- package/scripts/check_compressed_paths.py +6 -1
- package/scripts/check_council_layout.py +11 -0
- package/scripts/ci_time_ratio.py +168 -0
- package/scripts/council_cli.py +2005 -30
- package/scripts/install.sh +12 -0
- package/scripts/measure_projection_bytes.py +159 -0
- package/scripts/measure_roadmap_trajectory.py +112 -0
- package/scripts/probe_projection_fidelity.py +202 -0
- package/scripts/score_skill_selection.py +198 -0
- package/scripts/skill_collision_clusters.py +162 -0
- /package/scripts/{_backfill_skill_domains.py → _archive/_backfill_skill_domains.py} +0 -0
- /package/scripts/{_bootstrap_tier_frontmatter.py → _archive/_bootstrap_tier_frontmatter.py} +0 -0
- /package/scripts/{_p43_bodies.py → _archive/_p43_bodies.py} +0 -0
- /package/scripts/{_p43_compress.py → _archive/_p43_compress.py} +0 -0
- /package/scripts/{_p4_migrate.py → _archive/_p4_migrate.py} +0 -0
- /package/scripts/{_phase2_shim_helper.py → _archive/_phase2_shim_helper.py} +0 -0
- /package/scripts/{_pilot_council_question.py → _archive/_pilot_council_question.py} +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Preview builder for ``/memory learn-low-impact`` (step-9 Phase 7).
|
|
2
|
+
|
|
3
|
+
Default invocation is ``--preview``: build a structured plan describing
|
|
4
|
+
which Validated entries would be upstreamed to the package seed without
|
|
5
|
+
opening a PR. ``--apply`` (handled by the agent, not this module) is the
|
|
6
|
+
explicit opt-in that triggers the actual upstream-contribute PR flow.
|
|
7
|
+
|
|
8
|
+
The module is import-light by design — pure parsing + redaction + diff
|
|
9
|
+
rendering. PR creation lives in the ``upstream-contribute`` skill;
|
|
10
|
+
this module only hands the agent the material to surface.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Iterable
|
|
19
|
+
|
|
20
|
+
from scripts.ai_council.low_impact_corpus import (
|
|
21
|
+
CorpusEntry,
|
|
22
|
+
parse_corpus_strict,
|
|
23
|
+
)
|
|
24
|
+
from scripts.ai_council.redact_low_impact_entry import (
|
|
25
|
+
RedactionViolation,
|
|
26
|
+
redact_low_impact_entry,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_PROVENANCE_RE = re.compile(r"^last-upstreamed:\s*([0-9a-f]{6,40}|0+)\s*$",
|
|
31
|
+
re.IGNORECASE | re.MULTILINE)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class PreviewEntry:
|
|
36
|
+
"""One Validated bullet that would be upstreamed."""
|
|
37
|
+
phrase: str
|
|
38
|
+
normalised: str
|
|
39
|
+
line_no: int
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class RefusedEntry:
|
|
44
|
+
"""A Validated bullet the redactor refused — never upstreams."""
|
|
45
|
+
phrase: str
|
|
46
|
+
line_no: int
|
|
47
|
+
violations: tuple[RedactionViolation, ...]
|
|
48
|
+
|
|
49
|
+
def reason(self) -> str:
|
|
50
|
+
return "; ".join(f"{v.category}: {v.snippet}" for v in self.violations)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class LearnLowImpactPreview:
|
|
55
|
+
"""Structured preview for ``/memory learn-low-impact --preview``.
|
|
56
|
+
|
|
57
|
+
Consumed by the agent which renders the human-facing preview block,
|
|
58
|
+
then waits for explicit ``--apply`` before invoking
|
|
59
|
+
:doc:`upstream-contribute </skills/upstream-contribute/SKILL>`.
|
|
60
|
+
"""
|
|
61
|
+
promoted: tuple[PreviewEntry, ...]
|
|
62
|
+
refused: tuple[RefusedEntry, ...]
|
|
63
|
+
already_seeded: tuple[str, ...]
|
|
64
|
+
last_upstreamed_sha: str
|
|
65
|
+
seed_path: str
|
|
66
|
+
corpus_path: str
|
|
67
|
+
repo_slug: str = ""
|
|
68
|
+
warnings: tuple[str, ...] = field(default_factory=tuple)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def has_work(self) -> bool:
|
|
72
|
+
return bool(self.promoted) or bool(self.refused)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def would_open_pr(self) -> bool:
|
|
76
|
+
"""True when ``--apply`` would actually open a PR.
|
|
77
|
+
|
|
78
|
+
Iron Law: any redactor refusal blocks the PR — the author must
|
|
79
|
+
rephrase or drop the offending entry locally and re-run.
|
|
80
|
+
"""
|
|
81
|
+
return bool(self.promoted) and not self.refused
|
|
82
|
+
|
|
83
|
+
def render(self) -> str:
|
|
84
|
+
"""Human-readable preview block.
|
|
85
|
+
|
|
86
|
+
Mirrors the rendering convention from ``/memory mine-session``:
|
|
87
|
+
a leading title line, then bucketed entries.
|
|
88
|
+
"""
|
|
89
|
+
lines: list[str] = []
|
|
90
|
+
lines.append(
|
|
91
|
+
"## learn-low-impact preview"
|
|
92
|
+
+ (f" — repo={self.repo_slug}" if self.repo_slug else "")
|
|
93
|
+
)
|
|
94
|
+
lines.append(f"last-upstreamed: {self.last_upstreamed_sha}")
|
|
95
|
+
lines.append(f"seed: {self.seed_path}")
|
|
96
|
+
lines.append("")
|
|
97
|
+
if self.promoted:
|
|
98
|
+
lines.append(f"### Promoted ({len(self.promoted)})")
|
|
99
|
+
for e in self.promoted:
|
|
100
|
+
lines.append(f"- \"{e.phrase}\" (line {e.line_no})")
|
|
101
|
+
lines.append("")
|
|
102
|
+
if self.refused:
|
|
103
|
+
lines.append(f"### Refused ({len(self.refused)}) — redactor blocked")
|
|
104
|
+
for r in self.refused:
|
|
105
|
+
lines.append(
|
|
106
|
+
f"- \"{r.phrase}\" (line {r.line_no}) — {r.reason()}"
|
|
107
|
+
)
|
|
108
|
+
lines.append("")
|
|
109
|
+
if self.already_seeded:
|
|
110
|
+
lines.append(f"### Already seeded ({len(self.already_seeded)})")
|
|
111
|
+
for phrase in self.already_seeded:
|
|
112
|
+
lines.append(f"- \"{phrase}\"")
|
|
113
|
+
lines.append("")
|
|
114
|
+
if not self.has_work:
|
|
115
|
+
lines.append("> No new validated entries to upstream.")
|
|
116
|
+
lines.append("")
|
|
117
|
+
if self.refused:
|
|
118
|
+
lines.append(
|
|
119
|
+
"> Refusals block the PR. Rephrase the entries locally"
|
|
120
|
+
" (or drop them) and re-run."
|
|
121
|
+
)
|
|
122
|
+
elif self.promoted:
|
|
123
|
+
lines.append(
|
|
124
|
+
"> Re-run with `--apply` to open the draft PR via"
|
|
125
|
+
" `upstream-contribute`."
|
|
126
|
+
)
|
|
127
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
128
|
+
|
|
129
|
+
def render_diff(self) -> str:
|
|
130
|
+
"""Source-project-stripped diff that ``--apply`` would propose.
|
|
131
|
+
|
|
132
|
+
Emits unified-diff-style ``+`` lines for each promoted phrase
|
|
133
|
+
under the seed file's ``## Validated`` section. The agent uses
|
|
134
|
+
this as the ``upstream-contribute`` patch body.
|
|
135
|
+
"""
|
|
136
|
+
if not self.promoted:
|
|
137
|
+
return ""
|
|
138
|
+
lines = [f"--- {self.seed_path}", f"+++ {self.seed_path}"]
|
|
139
|
+
for e in self.promoted:
|
|
140
|
+
lines.append(f'+- "{e.phrase}"')
|
|
141
|
+
return "\n".join(lines) + "\n"
|
|
142
|
+
|
|
143
|
+
def render_pr_body(self) -> str:
|
|
144
|
+
"""Draft PR body for the upstream contribute flow."""
|
|
145
|
+
n = len(self.promoted)
|
|
146
|
+
slug = self.repo_slug or "<repo-slug>"
|
|
147
|
+
title = f"feat(low-impact-seed): add {n} validated entries from {slug}"
|
|
148
|
+
body_lines: list[str] = [
|
|
149
|
+
f"# {title}",
|
|
150
|
+
"",
|
|
151
|
+
"Upstream from `/memory learn-low-impact --apply`.",
|
|
152
|
+
"",
|
|
153
|
+
"## Entries",
|
|
154
|
+
"",
|
|
155
|
+
]
|
|
156
|
+
for e in self.promoted:
|
|
157
|
+
body_lines.append(f'- "{e.phrase}"')
|
|
158
|
+
body_lines.append("")
|
|
159
|
+
body_lines.append(
|
|
160
|
+
f"Provenance baseline: `{self.last_upstreamed_sha}`."
|
|
161
|
+
)
|
|
162
|
+
body_lines.append("")
|
|
163
|
+
body_lines.append(
|
|
164
|
+
"Per `low-impact-corpus-privacy-floor`, every entry above"
|
|
165
|
+
" cleared the redactor on intake and again at upstream."
|
|
166
|
+
)
|
|
167
|
+
return "\n".join(body_lines) + "\n"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _read_seed_phrases(seed_path: Path) -> set[str]:
|
|
171
|
+
"""Return the set of normalised phrases already in the seed file.
|
|
172
|
+
|
|
173
|
+
Missing seed file is not an error — it returns an empty set so the
|
|
174
|
+
first-ever upstream PR can seed the whole corpus. Reuses the
|
|
175
|
+
strict parser so the seed itself is contract-validated.
|
|
176
|
+
"""
|
|
177
|
+
if not seed_path.exists():
|
|
178
|
+
return set()
|
|
179
|
+
result = parse_corpus_strict(seed_path)
|
|
180
|
+
return {e.normalised for e in result.validated}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _read_provenance(corpus_path: Path) -> str:
|
|
184
|
+
if not corpus_path.exists():
|
|
185
|
+
return "0" * 40
|
|
186
|
+
text = corpus_path.read_text(encoding="utf-8")
|
|
187
|
+
m = _PROVENANCE_RE.search(text)
|
|
188
|
+
return m.group(1).lower() if m else "0" * 40
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def build_preview(
|
|
192
|
+
corpus_path: "object",
|
|
193
|
+
seed_path: "object",
|
|
194
|
+
*,
|
|
195
|
+
repo_root: str | None = None,
|
|
196
|
+
private_domains: Iterable[str] = (),
|
|
197
|
+
customer_names: Iterable[str] = (),
|
|
198
|
+
sql_identifiers: Iterable[str] = (),
|
|
199
|
+
repo_slug: str = "",
|
|
200
|
+
) -> LearnLowImpactPreview:
|
|
201
|
+
"""Build the preview plan without performing any PR side-effects.
|
|
202
|
+
|
|
203
|
+
Steps mirror the command doc:
|
|
204
|
+
|
|
205
|
+
1. Parse the local corpus (strict — drift surfaces as ParseError).
|
|
206
|
+
Step-10: the preview deliberately stays on the Markdown parser
|
|
207
|
+
(not the YAML lockfile) because it runs *before* ``task sync``
|
|
208
|
+
rebuilds the lockfile from a user's local corpus edits.
|
|
209
|
+
2. Diff Validated entries against the upstream seed.
|
|
210
|
+
3. Run the redactor on every candidate.
|
|
211
|
+
4. Bucket into promoted / refused / already-seeded.
|
|
212
|
+
"""
|
|
213
|
+
corpus_p = Path(str(corpus_path))
|
|
214
|
+
seed_p = Path(str(seed_path))
|
|
215
|
+
parsed = parse_corpus_strict(corpus_p)
|
|
216
|
+
seeded = _read_seed_phrases(seed_p)
|
|
217
|
+
promoted: list[PreviewEntry] = []
|
|
218
|
+
refused: list[RefusedEntry] = []
|
|
219
|
+
already: list[str] = []
|
|
220
|
+
for entry in parsed.validated:
|
|
221
|
+
if entry.normalised in seeded:
|
|
222
|
+
already.append(entry.phrase)
|
|
223
|
+
continue
|
|
224
|
+
result = redact_low_impact_entry(
|
|
225
|
+
entry.phrase,
|
|
226
|
+
repo_root=repo_root,
|
|
227
|
+
private_domains=private_domains,
|
|
228
|
+
customer_names=customer_names,
|
|
229
|
+
sql_identifiers=sql_identifiers,
|
|
230
|
+
)
|
|
231
|
+
if result.ok:
|
|
232
|
+
promoted.append(PreviewEntry(
|
|
233
|
+
phrase=entry.phrase,
|
|
234
|
+
normalised=entry.normalised,
|
|
235
|
+
line_no=entry.line_no,
|
|
236
|
+
))
|
|
237
|
+
else:
|
|
238
|
+
refused.append(RefusedEntry(
|
|
239
|
+
phrase=entry.phrase,
|
|
240
|
+
line_no=entry.line_no,
|
|
241
|
+
violations=result.violations,
|
|
242
|
+
))
|
|
243
|
+
return LearnLowImpactPreview(
|
|
244
|
+
promoted=tuple(promoted),
|
|
245
|
+
refused=tuple(refused),
|
|
246
|
+
already_seeded=tuple(already),
|
|
247
|
+
last_upstreamed_sha=_read_provenance(corpus_p),
|
|
248
|
+
seed_path=str(seed_p),
|
|
249
|
+
corpus_path=str(corpus_p),
|
|
250
|
+
repo_slug=repo_slug,
|
|
251
|
+
warnings=parsed.warnings,
|
|
252
|
+
)
|