@event4u/agent-config 7.1.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.claude-plugin/marketplace.json +2 -1
  2. package/CHANGELOG.md +80 -0
  3. package/README.md +9 -10
  4. package/dist/agent-src/rules/brand-source-of-truth.md +10 -0
  5. package/dist/agent-src/rules/delegation-policy.md +1 -0
  6. package/dist/agent-src/rules/legal-safety-floor.md +42 -4
  7. package/dist/agent-src/rules/output-discipline.md +85 -0
  8. package/dist/agent-src/rules/telegraph-speak.md +4 -1
  9. package/dist/agent-src/rules/token-budget-discipline.md +94 -0
  10. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +20 -5
  11. package/dist/agent-src/skills/blade-ui/SKILL.md +9 -0
  12. package/dist/agent-src/skills/bug-analyzer/evals/evals.json +13 -0
  13. package/dist/agent-src/skills/code-review/evals/evals.json +21 -0
  14. package/dist/agent-src/skills/contract-review/SKILL.md +3 -2
  15. package/dist/agent-src/skills/dashboard-design/SKILL.md +21 -5
  16. package/dist/agent-src/skills/design-intelligence/SKILL.md +96 -0
  17. package/dist/agent-src/skills/design-review/SKILL.md +83 -0
  18. package/dist/agent-src/skills/design-system-capture/SKILL.md +234 -0
  19. package/dist/agent-src/skills/design-tokens/SKILL.md +1 -0
  20. package/dist/agent-src/skills/dpa-review/SKILL.md +3 -2
  21. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +15 -4
  22. package/dist/agent-src/skills/fe-design/SKILL.md +98 -16
  23. package/dist/agent-src/skills/flux/SKILL.md +8 -0
  24. package/dist/agent-src/skills/iconography/SKILL.md +1 -0
  25. package/dist/agent-src/skills/legal-intake-triage/SKILL.md +3 -2
  26. package/dist/agent-src/skills/legal-practice-profile/SKILL.md +3 -2
  27. package/dist/agent-src/skills/livewire/SKILL.md +8 -0
  28. package/dist/agent-src/skills/nda-triage/SKILL.md +3 -2
  29. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +21 -9
  30. package/dist/agent-src/skills/skill-writing/SKILL.md +18 -0
  31. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +7 -10
  32. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +17 -7
  33. package/dist/agent-src/skills/typography-system/SKILL.md +14 -0
  34. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -0
  35. package/dist/discovery/deprecation-report.md +1 -1
  36. package/dist/discovery/discovery-manifest.json +123 -59
  37. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  38. package/dist/discovery/discovery-manifest.summary.md +8 -8
  39. package/dist/discovery/orphan-report.md +1 -1
  40. package/dist/discovery/packs.json +18 -15
  41. package/dist/discovery/trust-report.md +5 -5
  42. package/dist/discovery/workspaces.json +15 -12
  43. package/dist/mcp/registry-manifest.json +3 -3
  44. package/dist/router.json +1 -1
  45. package/dist/server/routes/wizard.js +4 -3
  46. package/dist/server/routes/wizard.js.map +1 -1
  47. package/dist/server/schemas/settings.js +9 -0
  48. package/dist/server/schemas/settings.js.map +1 -1
  49. package/dist/ui/assets/{index-CoQo90sz.js → index-UjcTG_9O.js} +2 -2
  50. package/dist/ui/assets/index-UjcTG_9O.js.map +1 -0
  51. package/dist/ui/index.html +1 -1
  52. package/docs/RELEASE_STORY_TEMPLATE.md +37 -0
  53. package/docs/architecture.md +3 -3
  54. package/docs/contracts/capability-boundary.md +64 -0
  55. package/docs/contracts/discovery-manifest.schema.json +2 -2
  56. package/docs/contracts/governance-enforcement-projection.md +154 -0
  57. package/docs/contracts/package-self-orientation.md +3 -0
  58. package/docs/contracts/subagent-boundary.md +54 -0
  59. package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +13 -0
  60. package/docs/decisions/ADR-107-legal-domain-pack-adoption.md +19 -0
  61. package/docs/enforcement-by-host.md +35 -0
  62. package/docs/getting-started.md +1 -1
  63. package/docs/guidelines/agent-infra/domain-pack-architecture.md +1 -0
  64. package/docs/guidelines/design-antipatterns-triggers.json +17 -0
  65. package/docs/guidelines/design-antipatterns.md +170 -0
  66. package/docs/guidelines/design-modes.md +97 -0
  67. package/package.json +1 -1
  68. package/src/config/agent-settings.template.yml +31 -0
  69. package/src/config/discovery/packs.yml +16 -5
  70. package/src/config/discovery/workspaces.yml +4 -4
  71. package/src/scripts/_lib/eval_discrimination.ts +95 -0
  72. package/src/scripts/_lib/trigger_routers.ts +268 -0
  73. package/src/scripts/bench_ab_v2_run.ts +38 -0
  74. package/src/scripts/check_trunk_drift.ts +67 -0
  75. package/src/scripts/cross_model_smoke.ts +245 -0
  76. package/src/scripts/lint_design_quality.ts +321 -0
  77. package/src/scripts/lint_discovery_vocabulary.ts +4 -4
  78. package/src/scripts/lint_legal_pack.ts +62 -4
  79. package/src/scripts/lint_output_slop.ts +223 -0
  80. package/src/scripts/lint_pack_risk_class.ts +79 -0
  81. package/src/scripts/run_skill_evals.ts +38 -0
  82. package/src/scripts/schemas/agent-settings.schema.json +12 -0
  83. package/src/scripts/schemas/skill.schema.json +5 -0
  84. package/src/scripts/skill_linter.ts +26 -10
  85. package/dist/ui/assets/index-CoQo90sz.js.map +0 -1
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Lint the `risk_class` invariant on packs (road-to-capability-governance Phase 2).
3
+ *
4
+ * `risk_class: high` is the regulated-advice-adjacent tier. A high-risk pack MUST
5
+ * ship conservatively — off by default, consent-gated, lab-tier — or it is a
6
+ * governance hole. This linter makes that invariant a hard CI failure.
7
+ *
8
+ * high ⇒ default_install: false AND requires_explicit_consent: true AND surface_tier: lab
9
+ *
10
+ * `medium` / `low` carry no structural requirement here (their disclaimers live
11
+ * in the domain safety floors). Absent `risk_class` = `low`.
12
+ *
13
+ * Pure core (`riskClassViolations`) takes the packs.yml text so it is unit-testable
14
+ * without the filesystem. Exit 0 = clean, 1 = at least one violation.
15
+ */
16
+
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+ import { fileURLToPath, pathToFileURL } from 'node:url';
20
+
21
+ const QUIET = process.argv.includes('--quiet');
22
+ const _HERE = fileURLToPath(import.meta.url);
23
+ const REPO = path.resolve(path.dirname(_HERE), '..', '..');
24
+ const PACKS_YML = path.join(REPO, 'src', 'config', 'discovery', 'packs.yml');
25
+
26
+ export interface RiskViolation {
27
+ pack: string;
28
+ msg: string;
29
+ }
30
+
31
+ function _field(block: string, key: string): string | undefined {
32
+ return new RegExp(`(^|\\n)\\s*${key}:\\s*([^\\n#]+)`).exec(block)?.[2]?.trim();
33
+ }
34
+
35
+ /** Pure invariant check over packs.yml text. */
36
+ export function riskClassViolations(packsYml: string): RiskViolation[] {
37
+ const out: RiskViolation[] = [];
38
+ // Split into per-pack blocks on top-level `- id:` entries.
39
+ const re = /(^|\n)- id:\s*([^\n#]+?)\s*\n([\s\S]*?)(?=\n- id:|\n*$)/g;
40
+ let m: RegExpExecArray | null;
41
+ while ((m = re.exec(packsYml)) !== null) {
42
+ const id = (m[2] ?? '').trim();
43
+ const block = m[3] ?? '';
44
+ const risk = _field(block, 'risk_class') ?? 'low';
45
+ if (risk !== 'high') continue;
46
+ const checks: Array<[string, string, string]> = [
47
+ ['default_install', 'false', `${id}: risk_class high requires default_install: false`],
48
+ ['requires_explicit_consent', 'true', `${id}: risk_class high requires requires_explicit_consent: true`],
49
+ ['surface_tier', 'lab', `${id}: risk_class high requires surface_tier: lab`],
50
+ ];
51
+ for (const [key, want, msg] of checks) {
52
+ if (_field(block, key) !== want) out.push({ pack: id, msg });
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+
58
+ function _print(s: string): void {
59
+ if (!QUIET) process.stdout.write(`${s}\n`);
60
+ }
61
+
62
+ export function main(): number {
63
+ if (!fs.existsSync(PACKS_YML)) {
64
+ _print('⚠️ packs.yml not found — skipping risk_class lint');
65
+ return 0;
66
+ }
67
+ const violations = riskClassViolations(fs.readFileSync(PACKS_YML, 'utf-8'));
68
+ if (violations.length === 0) {
69
+ _print('✅ risk_class invariant OK — every high-risk pack is off-by-default + consent + lab');
70
+ return 0;
71
+ }
72
+ _print(`❌ risk_class invariant — ${violations.length} violation(s):`);
73
+ for (const v of violations) _print(` - ${v.msg}`);
74
+ return 1;
75
+ }
76
+
77
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
78
+ process.exit(main());
79
+ }
@@ -97,6 +97,39 @@ export function _spawn_subagent(
97
97
  );
98
98
  }
99
99
 
100
+ /**
101
+ * Count "findings" in an eval output for the `finding_floor` assertion
102
+ * (roadmap `road-to-operator-runtime-harvest`, Phase 1). With an explicit
103
+ * `pattern`, counts non-overlapping global regex matches; without one, counts
104
+ * markdown list-item lines (the default shape a skill's findings take).
105
+ *
106
+ * Deterministic on purpose: this only *counts*. The substantive judgement —
107
+ * is each match a real finding, and what should `n` be per host — is the
108
+ * calibration layer (Phase 1 gold set + per-host floor), which is gated on the
109
+ * P0 cross-model distributions and therefore NOT wired here yet. So
110
+ * `finding_floor` is available as a mechanism and exercised by fixtures, but is
111
+ * not an enforcing CI gate until calibrated.
112
+ */
113
+ export function _count_findings(output: string, pattern?: string): number {
114
+ if (pattern !== undefined && pattern !== '') {
115
+ let re: RegExp;
116
+ try {
117
+ re = new RegExp(pattern, 'g');
118
+ } catch {
119
+ return 0;
120
+ }
121
+ const m = output.match(re);
122
+ return m ? m.length : 0;
123
+ }
124
+ let count = 0;
125
+ for (const line of output.split('\n')) {
126
+ if (/^\s*(?:[-*+]|\d+[.)])\s+\S/.test(line)) {
127
+ count += 1;
128
+ }
129
+ }
130
+ return count;
131
+ }
132
+
100
133
  export function _grade_assertions(
101
134
  output: string,
102
135
  run_dir: string,
@@ -119,6 +152,11 @@ export function _grade_assertions(
119
152
  pass: null,
120
153
  note: 'rubric grading requires sub-agent — fill in manually or via grader',
121
154
  });
155
+ } else if (kind === 'finding_floor') {
156
+ const n = (a['n'] as number | undefined) ?? 1;
157
+ const pattern = a['pattern'] as string | undefined;
158
+ const count = _count_findings(output, pattern);
159
+ results.push({ kind, n, count, pass: count >= n });
122
160
  } else {
123
161
  results.push({ kind: kind ?? null, pass: false, note: `unknown assertion kind ${_pyRepr(kind)}` });
124
162
  }
@@ -83,6 +83,18 @@
83
83
  "description": "How strictly the agent must follow a user-provided prototype / mockup / design system. Consumed by the design-fidelity rule. strict = build 1:1, every visible deviation needs confirmation; structural = structure locked, silent gaps fillable with a stated assumption; hard-floor = any deviation is never autonomous."
84
84
  }
85
85
  }
86
+ },
87
+ "tokens": {
88
+ "type": "object",
89
+ "additionalProperties": true,
90
+ "description": "Token-spend governance for skills marked token_budget_class: rich. See token-budget-discipline rule.",
91
+ "properties": {
92
+ "rich_skills": {
93
+ "type": "string",
94
+ "enum": ["on", "ask", "off"],
95
+ "description": "Controls whether skills marked token_budget_class: rich may load in full (exempt from telegraph-speak and thin-projector trimming). on = allowed (default); off = fall back to standard condensed behavior; ask = surface an estimated token delta (tokens, not dollars) and ask the user once per session before loading."
96
+ }
97
+ }
86
98
  }
87
99
  }
88
100
  }
@@ -182,6 +182,11 @@
182
182
  "removable": {"type": "boolean", "default": false}
183
183
  },
184
184
  "description": "ADR-013 install hints (default-on at consumer install; user-removable)."
185
+ },
186
+ "token_budget_class": {
187
+ "type": "string",
188
+ "enum": ["lean", "standard", "rich"],
189
+ "description": "Token-cost class for this skill. `lean` (default): subject to telegraph-speak condensation and thin-projector trimming; optimize for <500 tokens. `standard`: balanced guidance, normal condensation. `rich`: exempt from telegraph-speak and thin-projector trimming; detailed examples preserved; eager-load eligible; ≤15% of skills in a suite may be `rich` (CI-enforced). A `rich` skill MUST carry a '## Why this skill is rich' section explaining the irreducible complexity that makes condensation harmful. Governed by `token-budget-discipline` rule + `tokens.rich_skills` consumer setting. See docs/guidelines/token-budget-governance.md."
185
190
  }
186
191
  }
187
192
  }
@@ -1667,7 +1667,7 @@ export function validate_evals_json(skillPath: string): Issue[] {
1667
1667
  );
1668
1668
  return issues;
1669
1669
  }
1670
- const validKinds = ['contains', 'file_exists', 'rubric'];
1670
+ const validKinds = ['contains', 'file_exists', 'rubric', 'finding_floor'];
1671
1671
  const validKindsSet = new Set(validKinds);
1672
1672
  scenarios.forEach((scenario, idx) => {
1673
1673
  const loc = `scenarios[${idx}]`;
@@ -1709,15 +1709,31 @@ export function validate_evals_json(skillPath: string): Issue[] {
1709
1709
  );
1710
1710
  return;
1711
1711
  }
1712
- const requiredField = { contains: 'value', file_exists: 'path', rubric: 'criterion' }[kind] as string;
1713
- if (!(requiredField in a) || typeof a[requiredField] !== 'string') {
1714
- issues.push(
1715
- new Issue(
1716
- 'warning',
1717
- 'evals_json_assertion_missing_field',
1718
- `${aLoc} (kind=${kind}) missing required string field '${requiredField}'`,
1719
- ),
1720
- );
1712
+ if (kind === 'finding_floor') {
1713
+ // finding_floor (run_skill_evals): `n` (number; runtime-defaults to
1714
+ // 1) and `pattern` (regex string) are both OPTIONAL — validate type
1715
+ // only when present, require neither.
1716
+ if ('n' in a && typeof a.n !== 'number') {
1717
+ issues.push(
1718
+ new Issue('warning', 'evals_json_assertion_field_type', `${aLoc} (kind=finding_floor) 'n' must be a number`),
1719
+ );
1720
+ }
1721
+ if ('pattern' in a && typeof a.pattern !== 'string') {
1722
+ issues.push(
1723
+ new Issue('warning', 'evals_json_assertion_field_type', `${aLoc} (kind=finding_floor) 'pattern' must be a string`),
1724
+ );
1725
+ }
1726
+ } else {
1727
+ const requiredField = { contains: 'value', file_exists: 'path', rubric: 'criterion' }[kind] as string;
1728
+ if (!(requiredField in a) || typeof a[requiredField] !== 'string') {
1729
+ issues.push(
1730
+ new Issue(
1731
+ 'warning',
1732
+ 'evals_json_assertion_missing_field',
1733
+ `${aLoc} (kind=${kind}) missing required string field '${requiredField}'`,
1734
+ ),
1735
+ );
1736
+ }
1721
1737
  }
1722
1738
  });
1723
1739
  });