@event4u/agent-config 5.6.1 → 5.7.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/cost-report.md +12 -7
- package/.agent-src/commands/prediction-pool.md +215 -0
- package/.agent-src/commands/set-cost-profile.md +8 -8
- package/.agent-src/commands/sync-agent-settings.md +2 -2
- package/.agent-src/presets/README.md +1 -1
- package/.agent-src/profiles/README.md +1 -1
- package/.agent-src/rules/non-destructive-by-default.md +2 -1
- package/.agent-src/skills/prediction-pool-optimizer/SKILL.md +196 -0
- package/.agent-src/skills/prediction-pool-optimizer/evals/triggers.json +18 -0
- package/.agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +80 -0
- package/.agent-src/templates/agent-settings.md +7 -7
- package/.agent-src/templates/agents/agent-project-settings.example.yml +2 -2
- package/.agent-src/templates/scripts/work_engine/_lib/agent_settings.py +2 -1
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +1 -1
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +9 -7
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +9 -10
- package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +17 -4
- package/.claude-plugin/marketplace.json +3 -1
- package/CHANGELOG.md +48 -0
- package/README.md +2 -2
- package/config/agent-settings.template.yml +11 -2
- package/config/discovery/packs.yml +11 -0
- package/config/discovery/workspaces.yml +1 -1
- package/config/profiles/balanced.ini +1 -1
- package/config/profiles/full.ini +1 -1
- package/config/profiles/minimal.ini +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +80 -14
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -2
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +34 -3
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +13 -4
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/server/io/substituteTemplate.js +3 -3
- package/dist/server/io/substituteTemplate.js.map +1 -1
- package/dist/server/routes/settings.js +2 -2
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -2
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/ui/assets/{index-DVsyUMZe.js → index-5lFqAKL0.js} +2 -2
- package/dist/ui/assets/index-5lFqAKL0.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/architecture/current-onboard-baseline.md +3 -3
- package/docs/architecture.md +2 -2
- package/docs/catalog.md +7 -5
- package/docs/contracts/adr-level-6-productization.md +1 -1
- package/docs/contracts/config-presets.md +2 -2
- package/docs/contracts/cost-profile-defaults.md +5 -5
- package/docs/contracts/discovery-manifest.schema.json +1 -1
- package/docs/contracts/explain-trace.schema.json +3 -3
- package/docs/contracts/memory-visibility-v1.md +15 -7
- package/docs/contracts/profile-system.md +2 -2
- package/docs/contracts/settings-api.md +3 -3
- package/docs/contracts/value-report-schema.md +14 -1
- package/docs/customization.md +21 -5
- package/docs/decisions/ADR-010-profile-pack-preset-boundary.md +11 -11
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +16 -2
- package/docs/decisions/ADR-034-per-skill-model-recommendation-transport.md +1 -1
- package/docs/decisions/ADR-036-global-install-browser-wizard-handoff.md +106 -0
- package/docs/decisions/ADR-037-cost-profile-untangle.md +117 -0
- package/docs/decisions/ADR-rule-kernel-and-router.md +1 -1
- package/docs/decisions/INDEX.md +2 -0
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/layered-settings.md +2 -2
- package/docs/installation.md +3 -3
- package/docs/setup/mcp-client-config.md +1 -1
- package/docs/value.md +9 -7
- package/docs/wizard.md +1 -1
- package/package.json +1 -1
- package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/scripts/_cli/cmd_explain.py +1 -1
- package/scripts/_cli/explain_last/inputs.py +11 -8
- package/scripts/_cli/explain_last/sections/inputs.py +1 -1
- package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/scripts/_lib/agent_settings.py +2 -1
- package/scripts/_lib/value_ladder.py +99 -2
- package/scripts/_lib/value_report.py +30 -16
- package/scripts/ai_council/modes.py +1 -1
- package/scripts/audit_initial_context.py +16 -0
- package/scripts/check_skill_requires.py +143 -0
- package/scripts/condense.py +13 -2
- package/scripts/first-run.sh +11 -11
- package/scripts/install +14 -1
- package/scripts/install.py +127 -428
- package/scripts/install_anthropic_key.sh +1 -1
- package/scripts/install_openai_key.sh +1 -1
- package/scripts/lint_discovery_vocabulary.py +5 -5
- package/scripts/lint_value_dashboard.py +1 -1
- package/scripts/prediction-pool/adapters/_schema.md +42 -0
- package/scripts/prediction-pool/adapters/kicktipp.yml +23 -0
- package/scripts/prediction-pool/poisson_sim.py +167 -0
- package/scripts/render_value_md.py +1 -0
- package/scripts/schemas/agent-settings.schema.json +77 -0
- package/scripts/schemas/skill.schema.json +7 -0
- package/scripts/smoke_quickstart.py +4 -4
- package/scripts/sync_agent_settings.py +4 -2
- package/scripts/validate_agent_settings.py +120 -0
- package/templates/minimal/.agent-settings.yml +1 -1
- package/dist/ui/assets/index-DVsyUMZe.js.map +0 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Skill-composition graph gate (roadmap 3.4).
|
|
3
|
+
|
|
4
|
+
Validates the `requires_skills:` frontmatter field (the skill→skill
|
|
5
|
+
composition graph) against two invariants:
|
|
6
|
+
|
|
7
|
+
1. **Referential integrity** — every `requires_skills` target names a real
|
|
8
|
+
skill in the suite.
|
|
9
|
+
2. **Co-availability** — whenever a parent skill ships, every sub-skill its
|
|
10
|
+
body assumes must ship too. A sub-skill is co-available under a parent's
|
|
11
|
+
pack `P` iff one of the sub-skill's packs is in `{P}` ∪ the transitive
|
|
12
|
+
`requires_hint` closure of `P` (from `config/discovery/packs.yml`), or
|
|
13
|
+
the sub-skill is always-on (no pack). A parent with no pack (always-on)
|
|
14
|
+
may only require always-on sub-skills.
|
|
15
|
+
|
|
16
|
+
This is distinct from the ADR-015 artefact→pack `requires` field; this gate
|
|
17
|
+
operates on `requires_skills` (skill→skill) only.
|
|
18
|
+
|
|
19
|
+
Exit 0 = clean · 1 = at least one violation.
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
27
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent / "_lib"))
|
|
28
|
+
|
|
29
|
+
import yaml # noqa: E402
|
|
30
|
+
|
|
31
|
+
from _lib.agent_src import ROOT, iter_artefacts # noqa: E402
|
|
32
|
+
from validate_frontmatter import parse_frontmatter # noqa: E402
|
|
33
|
+
|
|
34
|
+
PACKS_YML = ROOT / "config" / "discovery" / "packs.yml"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _load_pack_closure() -> dict[str, set[str]]:
|
|
38
|
+
"""pack_id → transitive set of {self} ∪ requires_hint closure."""
|
|
39
|
+
raw = yaml.safe_load(PACKS_YML.read_text(encoding="utf-8")) or []
|
|
40
|
+
direct: dict[str, set[str]] = {}
|
|
41
|
+
for entry in raw:
|
|
42
|
+
pid = entry["id"]
|
|
43
|
+
direct[pid] = set(entry.get("requires_hint") or [])
|
|
44
|
+
|
|
45
|
+
closure: dict[str, set[str]] = {}
|
|
46
|
+
|
|
47
|
+
def resolve(pid: str, seen: set[str]) -> set[str]:
|
|
48
|
+
if pid in closure:
|
|
49
|
+
return closure[pid]
|
|
50
|
+
acc = {pid}
|
|
51
|
+
for dep in direct.get(pid, set()):
|
|
52
|
+
if dep in seen:
|
|
53
|
+
continue
|
|
54
|
+
acc |= resolve(dep, seen | {pid})
|
|
55
|
+
closure[pid] = acc
|
|
56
|
+
return acc
|
|
57
|
+
|
|
58
|
+
for pid in direct:
|
|
59
|
+
resolve(pid, set())
|
|
60
|
+
return closure
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _collect_skills() -> dict[str, dict]:
|
|
64
|
+
"""skill_id (directory name) → {packs: set[str], requires_skills: list[str], path}."""
|
|
65
|
+
skills: dict[str, dict] = {}
|
|
66
|
+
for path in iter_artefacts("SKILL.md"):
|
|
67
|
+
# logical id = the skill's directory name
|
|
68
|
+
skill_id = path.parent.name
|
|
69
|
+
fm, _ = parse_frontmatter(path.read_text(encoding="utf-8"))
|
|
70
|
+
if fm is None:
|
|
71
|
+
continue
|
|
72
|
+
skills[skill_id] = {
|
|
73
|
+
"packs": set(fm.get("packs") or []),
|
|
74
|
+
"requires_skills": list(fm.get("requires_skills") or []),
|
|
75
|
+
"path": path.relative_to(ROOT).as_posix(),
|
|
76
|
+
}
|
|
77
|
+
return skills
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def main() -> int:
|
|
81
|
+
closure = _load_pack_closure()
|
|
82
|
+
skills = _collect_skills()
|
|
83
|
+
errors: list[str] = []
|
|
84
|
+
|
|
85
|
+
for skill_id, info in sorted(skills.items()):
|
|
86
|
+
reqs = info["requires_skills"]
|
|
87
|
+
if not reqs:
|
|
88
|
+
continue
|
|
89
|
+
parent_packs: set[str] = info["packs"]
|
|
90
|
+
for req in reqs:
|
|
91
|
+
target = skills.get(req)
|
|
92
|
+
# (1) referential integrity
|
|
93
|
+
if target is None:
|
|
94
|
+
errors.append(
|
|
95
|
+
f"{info['path']}: requires_skills → unknown skill '{req}' "
|
|
96
|
+
f"(no skills/{req}/SKILL.md in the suite)."
|
|
97
|
+
)
|
|
98
|
+
continue
|
|
99
|
+
# (2) co-availability
|
|
100
|
+
req_packs: set[str] = target["packs"]
|
|
101
|
+
if not req_packs:
|
|
102
|
+
# always-on sub-skill is reachable from anywhere
|
|
103
|
+
continue
|
|
104
|
+
if not parent_packs:
|
|
105
|
+
# always-on parent may only require an always-on sub-skill
|
|
106
|
+
errors.append(
|
|
107
|
+
f"{info['path']}: always-on skill '{skill_id}' requires "
|
|
108
|
+
f"'{req}' which is pack-gated ({sorted(req_packs)}); a base "
|
|
109
|
+
f"install would ship '{skill_id}' without '{req}'."
|
|
110
|
+
)
|
|
111
|
+
continue
|
|
112
|
+
for p in sorted(parent_packs):
|
|
113
|
+
reachable = closure.get(p, {p})
|
|
114
|
+
if req_packs & reachable:
|
|
115
|
+
continue
|
|
116
|
+
hint = sorted(req_packs - reachable)
|
|
117
|
+
errors.append(
|
|
118
|
+
f"{info['path']}: skill '{skill_id}' (pack '{p}') requires "
|
|
119
|
+
f"'{req}' (pack {sorted(req_packs)}), but '{p}' does not reach "
|
|
120
|
+
f"it. Add requires_hint: {hint} to pack '{p}' in "
|
|
121
|
+
f"config/discovery/packs.yml, or move '{req}' into a reachable pack."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if errors:
|
|
125
|
+
print("❌ check_skill_requires: skill-composition graph has unmet edges:")
|
|
126
|
+
for e in errors:
|
|
127
|
+
print(f" 🔴 {e}")
|
|
128
|
+
print(
|
|
129
|
+
"\nEvery sub-skill a parent's body invokes must ship wherever the "
|
|
130
|
+
"parent ships. Declare the missing pack dependency or co-locate the skill."
|
|
131
|
+
)
|
|
132
|
+
return 1
|
|
133
|
+
|
|
134
|
+
n_edges = sum(len(i["requires_skills"]) for i in skills.values())
|
|
135
|
+
print(
|
|
136
|
+
f"✅ check_skill_requires: {n_edges} composition edge(s) across "
|
|
137
|
+
f"{sum(1 for i in skills.values() if i['requires_skills'])} skill(s) — all sub-skills co-available."
|
|
138
|
+
)
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
raise SystemExit(main())
|
package/scripts/condense.py
CHANGED
|
@@ -770,6 +770,17 @@ def _parse_frontmatter(content: str) -> tuple[dict, str]:
|
|
|
770
770
|
return meta if isinstance(meta, dict) else {}, body
|
|
771
771
|
|
|
772
772
|
|
|
773
|
+
def _yaml_scalar(value: str) -> str:
|
|
774
|
+
"""Return a YAML-safe single-line scalar for a frontmatter value.
|
|
775
|
+
|
|
776
|
+
Descriptions can contain ``:``, ``#``, or quotes — characters that break
|
|
777
|
+
an unquoted YAML scalar (e.g. ``description: Hard Floor: ...`` is invalid
|
|
778
|
+
YAML). A JSON string is itself a valid YAML double-quoted scalar, so
|
|
779
|
+
``json.dumps`` gives correct escaping for free.
|
|
780
|
+
"""
|
|
781
|
+
return json.dumps(value, ensure_ascii=False)
|
|
782
|
+
|
|
783
|
+
|
|
773
784
|
def _emit_cursor_mdc(source: Path, target: Path) -> None:
|
|
774
785
|
"""Write a Cursor `.mdc` file with Cursor-shaped frontmatter."""
|
|
775
786
|
meta, body = _parse_frontmatter(source.read_text())
|
|
@@ -777,7 +788,7 @@ def _emit_cursor_mdc(source: Path, target: Path) -> None:
|
|
|
777
788
|
always_apply = bool(meta.get("alwaysApply") or meta.get("type") == "always")
|
|
778
789
|
lines = [
|
|
779
790
|
"---",
|
|
780
|
-
f"description: {description}",
|
|
791
|
+
f"description: {_yaml_scalar(description)}",
|
|
781
792
|
"globs: ",
|
|
782
793
|
f"alwaysApply: {'true' if always_apply else 'false'}",
|
|
783
794
|
"---",
|
|
@@ -797,7 +808,7 @@ def _emit_windsurf_rule(source: Path, target: Path) -> None:
|
|
|
797
808
|
lines = [
|
|
798
809
|
"---",
|
|
799
810
|
f"trigger: {trigger}",
|
|
800
|
-
f"description: {description}",
|
|
811
|
+
f"description: {_yaml_scalar(description)}",
|
|
801
812
|
"globs: ",
|
|
802
813
|
"---",
|
|
803
814
|
"",
|
package/scripts/first-run.sh
CHANGED
|
@@ -9,14 +9,14 @@ echo "Agent Config — First Run"
|
|
|
9
9
|
echo ""
|
|
10
10
|
|
|
11
11
|
# --- Profile detection ---
|
|
12
|
-
# The YAML format stores `
|
|
13
|
-
#
|
|
12
|
+
# The YAML format stores `rule_loading_tier` as a top-level scalar:
|
|
13
|
+
# rule_loading_tier: minimal
|
|
14
14
|
# It may be unquoted or double-quoted after migration. We strip both.
|
|
15
|
-
|
|
15
|
+
read_rule_loading_tier() {
|
|
16
16
|
local file="$1"
|
|
17
|
-
grep -E '^
|
|
17
|
+
grep -E '^rule_loading_tier:' "$file" 2>/dev/null \
|
|
18
18
|
| head -n1 \
|
|
19
|
-
| sed -E 's/^
|
|
19
|
+
| sed -E 's/^rule_loading_tier:[[:space:]]*//' \
|
|
20
20
|
| sed -E 's/^"(.*)"$/\1/' \
|
|
21
21
|
| sed -E "s/^'(.*)'\$/\\1/" \
|
|
22
22
|
| tr -d '[:space:]'
|
|
@@ -25,16 +25,16 @@ read_cost_profile() {
|
|
|
25
25
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
26
26
|
echo "✅ Found $SETTINGS_FILE"
|
|
27
27
|
echo ""
|
|
28
|
-
CURRENT_PROFILE=$(
|
|
28
|
+
CURRENT_PROFILE=$(read_rule_loading_tier "$SETTINGS_FILE" || true)
|
|
29
29
|
|
|
30
30
|
if [ -n "${CURRENT_PROFILE:-}" ]; then
|
|
31
|
-
echo "Active
|
|
31
|
+
echo "Active rule_loading_tier: $CURRENT_PROFILE"
|
|
32
32
|
else
|
|
33
|
-
echo "No
|
|
33
|
+
echo "No rule_loading_tier configured yet."
|
|
34
34
|
echo ""
|
|
35
35
|
echo "Recommended: add this to $SETTINGS_FILE:"
|
|
36
36
|
echo ""
|
|
37
|
-
echo "
|
|
37
|
+
echo " rule_loading_tier: minimal"
|
|
38
38
|
fi
|
|
39
39
|
elif [ -f "$LEGACY_SETTINGS_FILE" ]; then
|
|
40
40
|
echo "⚠️ Found legacy $LEGACY_SETTINGS_FILE (key=value format)."
|
|
@@ -47,7 +47,7 @@ else
|
|
|
47
47
|
echo ""
|
|
48
48
|
echo "Create one with:"
|
|
49
49
|
echo ""
|
|
50
|
-
echo "
|
|
50
|
+
echo " rule_loading_tier: minimal"
|
|
51
51
|
echo ""
|
|
52
52
|
fi
|
|
53
53
|
|
|
@@ -97,7 +97,7 @@ echo " minimal rules, skills, commands only"
|
|
|
97
97
|
echo " balanced + runtime dispatcher"
|
|
98
98
|
echo " full + experimental read-only tool adapters"
|
|
99
99
|
echo ""
|
|
100
|
-
echo "Change profile: edit
|
|
100
|
+
echo "Change profile: edit rule_loading_tier: <name> in $SETTINGS_FILE"
|
|
101
101
|
echo "Profile details: docs/customization.md"
|
|
102
102
|
echo "Getting started: docs/getting-started.md"
|
|
103
103
|
echo ""
|
package/scripts/install
CHANGED
|
@@ -232,7 +232,20 @@ prompt_tools() {
|
|
|
232
232
|
echo " ✅ Selected: $TOOLS"
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
# When an interactive global install will hand off to the browser wizard,
|
|
236
|
+
# the wizard is the single tool-selection surface — skip the terminal
|
|
237
|
+
# picker so it does not pre-empt (and, via TOOLS_EXPLICIT, suppress) the
|
|
238
|
+
# GUI. Mirrors install.py::_wizard_should_launch minus the --no-ui flag,
|
|
239
|
+
# which the bash orchestrator never receives (it errors on unknown args).
|
|
240
|
+
# Headless paths (no TTY / CI / AGENT_CONFIG_NO_UI) still get the picker.
|
|
241
|
+
wizard_will_handle_tools=false
|
|
242
|
+
if $GLOBAL && [[ -t 0 && -t 1 && -z "${CI:-}" ]] \
|
|
243
|
+
&& { [[ -z "${AGENT_CONFIG_NO_UI:-}" ]] || [[ "${AGENT_CONFIG_NO_UI:-}" == "0" ]]; }; then
|
|
244
|
+
wizard_will_handle_tools=true
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
if ! $MINIMAL && ! $TOOLS_EXPLICIT && ! $YES && ! $QUIET && ! $LIST_TOOLS \
|
|
248
|
+
&& [[ -t 0 && -t 1 ]] && ! $wizard_will_handle_tools; then
|
|
236
249
|
prompt_tools
|
|
237
250
|
TOOLS_EXPLICIT=true
|
|
238
251
|
fi
|