@event4u/agent-config 9.15.0 → 9.17.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 (157) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +1 -1
  3. package/CHANGELOG.md +74 -0
  4. package/README.md +1 -1
  5. package/dist/agent-src/commands/agent-handoff.md +100 -48
  6. package/dist/agent-src/commands/commit.md +1 -1
  7. package/dist/agent-src/commands/condense.md +19 -64
  8. package/dist/agent-src/commands/evals/agent-handoff.json +13 -1
  9. package/dist/agent-src/commands/memory/promote.md +14 -1
  10. package/dist/agent-src/commands/mode.md +9 -5
  11. package/dist/agent-src/commands/optimize/deep.md +72 -11
  12. package/dist/agent-src/contexts/authority/commit-mechanics.md +5 -5
  13. package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
  14. package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
  15. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +6 -1
  16. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +4 -1
  17. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +27 -1
  18. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +5 -2
  19. package/dist/agent-src/profiles/agency.yml +3 -3
  20. package/dist/agent-src/profiles/content_creator.yml +2 -2
  21. package/dist/agent-src/profiles/developer.yml +2 -2
  22. package/dist/agent-src/profiles/finance.yml +1 -1
  23. package/dist/agent-src/profiles/founder.yml +2 -2
  24. package/dist/agent-src/profiles/ops.yml +2 -2
  25. package/dist/agent-src/rules/architecture.md +2 -2
  26. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  27. package/dist/agent-src/rules/context-hygiene.md +3 -2
  28. package/dist/agent-src/rules/domain-safety-pii.md +1 -1
  29. package/dist/agent-src/rules/output-discipline.md +9 -2
  30. package/dist/agent-src/rules/token-budget-discipline.md +2 -2
  31. package/dist/agent-src/rules/user-interaction.md +3 -4
  32. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
  33. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +4 -4
  34. package/dist/agent-src/skills/copilot-config/SKILL.md +1 -1
  35. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +7 -4
  36. package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
  37. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  38. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
  39. package/dist/agent-src/skills/persona-writing/SKILL.md +2 -2
  40. package/dist/agent-src/skills/readme-reviewer/SKILL.md +2 -1
  41. package/dist/agent-src/skills/rule-writing/SKILL.md +4 -2
  42. package/dist/agent-src/skills/skill-reviewer/SKILL.md +1 -1
  43. package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
  44. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
  45. package/dist/agent-src/skills/token-optimizer/SKILL.md +2 -2
  46. package/dist/agent-src/skills/ui-component-architect/SKILL.md +6 -3
  47. package/dist/agent-src/templates/agent-settings.md +13 -15
  48. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +6 -2
  49. package/dist/agent-src/templates/persona.md +2 -2
  50. package/dist/agent-src/templates/roadmaps.md +1 -1
  51. package/dist/agent-src/templates/rule.md +1 -1
  52. package/dist/agent-src/templates/skill.md +1 -1
  53. package/dist/cli/mcp/content.js +1 -1
  54. package/dist/cli/mcp/content.js.map +1 -1
  55. package/dist/cli/registry.js +1 -0
  56. package/dist/cli/registry.js.map +1 -1
  57. package/dist/cli-delegate/{chunk-ZXXJLL5K.js → chunk-BSLUHV2F.js} +127 -1487
  58. package/dist/cli-delegate/{chunk-H574KOUH.js → chunk-IMSXPRVH.js} +24 -1
  59. package/dist/cli-delegate/chunk-VSYT7OHO.js +1382 -0
  60. package/dist/cli-delegate/chunk-XGA2NTU4.js +3727 -0
  61. package/dist/cli-delegate/cmd_conformance.js +4 -3
  62. package/dist/cli-delegate/cmd_converge.js +3 -3
  63. package/dist/cli-delegate/cmd_doctor.js +3 -2
  64. package/dist/cli-delegate/cmd_export.js +4 -4
  65. package/dist/cli-delegate/cmd_handoff.js +3194 -0
  66. package/dist/cli-delegate/cmd_memory_get.js +35 -3754
  67. package/dist/cli-delegate/cmd_migrate.js +2 -2
  68. package/dist/cli-delegate/cmd_prune.js +4 -4
  69. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  70. package/dist/cli-delegate/cmd_sync.js +4 -4
  71. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  72. package/dist/cli-delegate/cmd_update.js +3 -3
  73. package/dist/cli-delegate/cmd_upgrade.js +3 -3
  74. package/dist/cli-delegate/cmd_validate.js +4 -4
  75. package/dist/cli-delegate/cmd_versions.js +3 -3
  76. package/dist/discovery/deprecation-report.md +1 -1
  77. package/dist/discovery/discovery-manifest.json +31 -31
  78. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  79. package/dist/discovery/discovery-manifest.summary.md +1 -1
  80. package/dist/discovery/orphan-report.md +1 -1
  81. package/dist/discovery/packs.json +2 -2
  82. package/dist/discovery/trust-report.md +1 -1
  83. package/dist/discovery/workspaces.json +2 -2
  84. package/dist/hooks/dispatch.js +602 -507
  85. package/dist/install/install.mjs +23 -0
  86. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  87. package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
  88. package/dist/mcp/registry-manifest.json +4 -4
  89. package/dist/mcp/server.json +2 -2
  90. package/dist/mcp/server.mjs +25 -3
  91. package/dist/scripts/_lib/agent_src.js +39 -6
  92. package/dist/scripts/_lib/agent_src.js.map +1 -1
  93. package/dist/server/routes/workspace.js +1 -1
  94. package/dist/server/routes/workspace.js.map +1 -1
  95. package/dist/server/schemas/settings.js +13 -0
  96. package/dist/server/schemas/settings.js.map +1 -1
  97. package/dist/shared/userMd/utils.js +1 -1
  98. package/dist/shared/userMd/utils.js.map +1 -1
  99. package/dist/ui/assets/index-DmR0mbk4.js +26 -0
  100. package/dist/ui/assets/index-DmR0mbk4.js.map +1 -0
  101. package/dist/ui/index.html +1 -1
  102. package/docs/guidelines/abstraction-thresholds.md +53 -0
  103. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -1
  104. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +7 -0
  105. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +2 -2
  106. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +5 -3
  107. package/docs/guidelines/agent-infra/size-and-scope.md +8 -2
  108. package/docs/guidelines/component-oriented-and-oop-development.md +11 -6
  109. package/docs/guidelines/docs/readme-size-and-splitting.md +5 -2
  110. package/llms.txt +1 -0
  111. package/package.json +4 -4
  112. package/src/config/agent-settings.template.yml +25 -1
  113. package/src/config/budget-routing.json +7 -0
  114. package/src/config/evaluator-budgets.json +8 -11
  115. package/src/config/gate-coverage.yml +30 -0
  116. package/src/scripts/_cli/cmd_handoff.ts +405 -0
  117. package/src/scripts/_cli/handoff_generate.ts +453 -0
  118. package/src/scripts/_cli/handoff_sessions.ts +435 -0
  119. package/src/scripts/_dispatch.bash +9 -0
  120. package/src/scripts/_lib/agent_src.ts +36 -6
  121. package/src/scripts/_lib/release_material.ts +156 -0
  122. package/src/scripts/_lib/tier_budget_routing.ts +154 -28
  123. package/src/scripts/anchor_scoring_run.ts +1 -1
  124. package/src/scripts/bench_persona_placebo.ts +1 -1
  125. package/src/scripts/bench_quality_run.ts +1 -1
  126. package/src/scripts/check_cli_registry_budget_sync.ts +168 -0
  127. package/src/scripts/check_condensation.ts +2 -1
  128. package/src/scripts/check_finding_dispositions.ts +278 -0
  129. package/src/scripts/check_gate_coverage.ts +1 -1
  130. package/src/scripts/check_pack_size.ts +4 -3
  131. package/src/scripts/check_references.ts +1 -0
  132. package/src/scripts/check_release_highlights.ts +300 -0
  133. package/src/scripts/check_release_pr_shape.ts +4 -0
  134. package/src/scripts/check_release_surface_equality.ts +132 -0
  135. package/src/scripts/check_reply_consistency.ts +187 -138
  136. package/src/scripts/check_token_quality_golden.ts +1 -1
  137. package/src/scripts/cost/budget.mjs +18 -4
  138. package/src/scripts/handoff_context_hook.ts +148 -0
  139. package/src/scripts/hook_manifest.yaml +17 -7
  140. package/src/scripts/hooks/concern_registry.ts +2 -0
  141. package/src/scripts/lint_abstraction_thresholds.ts +325 -0
  142. package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
  143. package/src/scripts/lint_profile_personas.ts +153 -0
  144. package/src/scripts/lint_token_budget_discipline.ts +148 -0
  145. package/src/scripts/release.ts +264 -37
  146. package/src/scripts/release_drill.ts +491 -0
  147. package/src/scripts/routing_doctor.ts +76 -1
  148. package/src/scripts/schemas/command.schema.json +33 -0
  149. package/src/scripts/self_review_gate.ts +41 -3
  150. package/src/scripts/skill_linter.ts +3 -1
  151. package/src/scripts/smoke/router.sh +1 -1
  152. package/src/scripts/update_counts.ts +60 -12
  153. package/src/server/schemas/settings.ts +23 -0
  154. package/src/shared/userMd/utils.ts +1 -1
  155. package/dist/ui/assets/index-DJY_vQVn.js +0 -40
  156. package/dist/ui/assets/index-DJY_vQVn.js.map +0 -1
  157. package/dist/cli-delegate/{chunk-XX6TOPD7.js → chunk-WR6GTRHJ.js} +3 -3
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Profile → persona id resolution gate.
4
+ *
5
+ * ## The defect this catches
6
+ *
7
+ * Every seed profile under `src/agent-src/profiles/*.yml` pre-selects persona
8
+ * ids in `defaults.personas`. Persona ids are the filenames under
9
+ * `src/agent-src/personas/` (plus `personas/advisors/`), and nothing else
10
+ * historically checked the join — all six seed profiles shipped ids
11
+ * (`reviewer`, `security`, `editor`, …) that resolved to no persona file at
12
+ * all, so the pre-selection was silently dead. This gate makes a broken id a
13
+ * CI failure with a nearest-match hint.
14
+ *
15
+ * Contract (src/config/gate-coverage.yml): emits exactly one `scanned: <N>`
16
+ * line, N = profiles scanned.
17
+ *
18
+ * Exit: 0 clean · 1 usage/IO error · 2 findings.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+ import { fileURLToPath, pathToFileURL } from 'node:url';
23
+ import { parse as parseYaml } from 'yaml';
24
+
25
+ const _HERE = fileURLToPath(import.meta.url);
26
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
27
+
28
+ export interface Finding {
29
+ file: string;
30
+ id: string;
31
+ hint: string;
32
+ }
33
+
34
+ /** Persona ids = `.md` basenames under personas/ and personas/advisors/. */
35
+ export function known_persona_ids(repoRoot: string): Set<string> {
36
+ const ids = new Set<string>();
37
+ const roots = [
38
+ path.join(repoRoot, 'src', 'agent-src', 'personas'),
39
+ path.join(repoRoot, 'src', 'agent-src', 'personas', 'advisors'),
40
+ ];
41
+ for (const dir of roots) {
42
+ if (!fs.existsSync(dir)) continue;
43
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
44
+ if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
45
+ if (entry.name === 'README.md') continue;
46
+ ids.add(entry.name.slice(0, -'.md'.length));
47
+ }
48
+ }
49
+ return ids;
50
+ }
51
+
52
+ function levenshtein(a: string, b: string): number {
53
+ const prev: number[] = Array.from({ length: b.length + 1 }, (_, i) => i);
54
+ for (let i = 1; i <= a.length; i++) {
55
+ let diag = prev[0]!;
56
+ prev[0] = i;
57
+ for (let j = 1; j <= b.length; j++) {
58
+ const cur = prev[j]!;
59
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
60
+ prev[j] = Math.min(cur + 1, prev[j - 1]! + 1, diag + cost);
61
+ diag = cur;
62
+ }
63
+ }
64
+ return prev[b.length]!;
65
+ }
66
+
67
+ /** Closest known id by substring containment first, edit distance second. */
68
+ export function nearest_match(id: string, known: ReadonlySet<string>): string {
69
+ let best = '';
70
+ let bestScore = Number.POSITIVE_INFINITY;
71
+ for (const candidate of known) {
72
+ const contains = candidate.includes(id) || id.includes(candidate);
73
+ const score = levenshtein(id, candidate) - (contains ? 100 : 0);
74
+ if (score < bestScore) {
75
+ bestScore = score;
76
+ best = candidate;
77
+ }
78
+ }
79
+ return best;
80
+ }
81
+
82
+ /**
83
+ * Scan every `profiles/*.yml` under `repoRoot`'s profile dir and resolve
84
+ * `defaults.personas` against the known persona ids.
85
+ */
86
+ export function scan_profiles(repoRoot: string): { findings: Finding[]; scanned: number } {
87
+ const profileDir = path.join(repoRoot, 'src', 'agent-src', 'profiles');
88
+ if (!fs.existsSync(profileDir)) {
89
+ throw new Error(`profile directory not found: ${profileDir}`);
90
+ }
91
+ const known = known_persona_ids(repoRoot);
92
+ const findings: Finding[] = [];
93
+ let scanned = 0;
94
+ const files = fs
95
+ .readdirSync(profileDir)
96
+ .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))
97
+ .sort();
98
+ for (const file of files) {
99
+ const full = path.join(profileDir, file);
100
+ const rel = path.relative(repoRoot, full);
101
+ const parsed = parseYaml(fs.readFileSync(full, 'utf-8')) as Record<string, unknown> | null;
102
+ scanned += 1;
103
+ const profile = (parsed?.['profile'] ?? {}) as Record<string, unknown>;
104
+ const defaults = (profile['defaults'] ?? {}) as Record<string, unknown>;
105
+ const personas = defaults['personas'];
106
+ if (!Array.isArray(personas)) continue;
107
+ for (const raw of personas) {
108
+ const id = String(raw);
109
+ if (known.has(id)) continue;
110
+ const hint = known.size > 0 ? `did you mean \`${nearest_match(id, known)}\`?` : 'no personas found';
111
+ findings.push({ file: rel, id, hint });
112
+ }
113
+ }
114
+ return { findings, scanned };
115
+ }
116
+
117
+ export function main(argv?: readonly string[]): number {
118
+ let quiet = false;
119
+ for (const arg of argv ?? process.argv.slice(2)) {
120
+ if (arg === '--quiet') {
121
+ quiet = true;
122
+ } else {
123
+ process.stderr.write(`usage: lint_profile_personas [--quiet]\n`);
124
+ return 1;
125
+ }
126
+ }
127
+
128
+ let result: { findings: Finding[]; scanned: number };
129
+ try {
130
+ result = scan_profiles(REPO_ROOT);
131
+ } catch (e) {
132
+ process.stderr.write(`error: ${String(e)}\n`);
133
+ return 1;
134
+ }
135
+
136
+ for (const f of result.findings) {
137
+ process.stdout.write(
138
+ `❌ ${f.file} defaults.personas id \`${f.id}\` resolves to no file under src/agent-src/personas/ — ${f.hint}\n`,
139
+ );
140
+ }
141
+ if (result.findings.length === 0 && !quiet) {
142
+ process.stdout.write(
143
+ `✅ profile personas: every defaults.personas id resolves to a persona file\n`,
144
+ );
145
+ }
146
+ // gate-coverage contract (src/config/gate-coverage.yml): profiles inspected.
147
+ process.stdout.write(`scanned: ${String(result.scanned)}\n`);
148
+ return result.findings.length > 0 ? 2 : 0;
149
+ }
150
+
151
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
152
+ process.exit(main());
153
+ }
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Token-budget-discipline gate (src/rules/token-budget-discipline.md).
4
+ *
5
+ * The rule names this linter as its CI enforcer for two obligations on
6
+ * `token_budget_class: rich` skills:
7
+ *
8
+ * 1. CAP — at most 15 % of the suite's skills may claim `rich`. Exceeding
9
+ * the ratio is a hard fail (both numbers are printed).
10
+ * 2. JUSTIFICATION — every `rich`-tagged skill carries a
11
+ * `## Why this skill is rich` section explaining the irreducible
12
+ * complexity.
13
+ *
14
+ * Additionally, any `token_budget_class` value outside
15
+ * `lean | standard | rich` is a finding (schema drift).
16
+ *
17
+ * Exit: 0 clean · 1 usage/IO error · 2 findings.
18
+ */
19
+ import * as fs from 'node:fs';
20
+ import * as path from 'node:path';
21
+ import { fileURLToPath, pathToFileURL } from 'node:url';
22
+
23
+ const _HERE = fileURLToPath(import.meta.url);
24
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
25
+
26
+ export const SKILLS_ROOT = 'src/skills';
27
+
28
+ /** The rule's cap: rich-tagged skills / total skills must stay <= 15 %. */
29
+ export const RICH_RATIO_CAP = 0.15;
30
+
31
+ export const VALID_CLASSES = ['lean', 'standard', 'rich'] as const;
32
+
33
+ export const RICH_SECTION_HEADING = '## Why this skill is rich';
34
+
35
+ export interface Finding {
36
+ /** repo-relative path */
37
+ file: string;
38
+ message: string;
39
+ }
40
+
41
+ export interface ScanResult {
42
+ findings: Finding[];
43
+ /** SKILL.md files scanned. */
44
+ scanned: number;
45
+ /** Skills declaring token_budget_class: rich. */
46
+ richCount: number;
47
+ }
48
+
49
+ /** `token_budget_class` value from a SKILL.md's YAML frontmatter, or null. */
50
+ export function frontmatter_class(content: string): string | null {
51
+ if (!content.startsWith('---')) {
52
+ return null;
53
+ }
54
+ const end = content.indexOf('\n---', 3);
55
+ if (end === -1) {
56
+ return null;
57
+ }
58
+ const frontmatter = content.slice(0, end);
59
+ const m = /^token_budget_class:\s*['"]?([^'"\s#]+)/m.exec(frontmatter);
60
+ return m ? m[1]! : null;
61
+ }
62
+
63
+ /** Scan one skills root (directory of `<skill>/SKILL.md`). */
64
+ export function scan_skills(skillsRoot: string): ScanResult {
65
+ const findings: Finding[] = [];
66
+ let scanned = 0;
67
+ let richCount = 0;
68
+ const entries = fs
69
+ .readdirSync(skillsRoot, { withFileTypes: true })
70
+ .filter((e) => e.isDirectory())
71
+ .map((e) => e.name)
72
+ .sort();
73
+ for (const name of entries) {
74
+ const skillFile = path.join(skillsRoot, name, 'SKILL.md');
75
+ if (!fs.existsSync(skillFile)) {
76
+ continue;
77
+ }
78
+ scanned += 1;
79
+ const rel = path.relative(REPO_ROOT, skillFile).split(path.sep).join('/');
80
+ const content = fs.readFileSync(skillFile, 'utf-8');
81
+ const cls = frontmatter_class(content);
82
+ if (cls === null) {
83
+ continue; // no key = lean by default (rule § the three classes)
84
+ }
85
+ if (!(VALID_CLASSES as readonly string[]).includes(cls)) {
86
+ findings.push({
87
+ file: rel,
88
+ message: `invalid token_budget_class '${cls}' — must be one of ${VALID_CLASSES.join(' | ')}`,
89
+ });
90
+ continue;
91
+ }
92
+ if (cls === 'rich') {
93
+ richCount += 1;
94
+ if (!content.includes(RICH_SECTION_HEADING)) {
95
+ findings.push({
96
+ file: rel,
97
+ message: `rich-tagged skill missing the '${RICH_SECTION_HEADING}' justification section`,
98
+ });
99
+ }
100
+ }
101
+ }
102
+ if (scanned > 0 && richCount > scanned * RICH_RATIO_CAP) {
103
+ findings.push({
104
+ file: SKILLS_ROOT,
105
+ message:
106
+ `rich-skill cap exceeded: ${String(richCount)} rich of ${String(scanned)} skills ` +
107
+ `(${((richCount / scanned) * 100).toFixed(1)} % > ${String(RICH_RATIO_CAP * 100)} % cap, ` +
108
+ `max ${String(Math.floor(scanned * RICH_RATIO_CAP))})`,
109
+ });
110
+ }
111
+ return { findings, scanned, richCount };
112
+ }
113
+
114
+ export function main(argv?: readonly string[]): number {
115
+ let quiet = false;
116
+ for (const arg of argv ?? process.argv.slice(2)) {
117
+ if (arg === '--quiet') {
118
+ quiet = true;
119
+ } else {
120
+ process.stderr.write('usage: lint_token_budget_discipline [--quiet]\n');
121
+ return 1;
122
+ }
123
+ }
124
+
125
+ let result: ScanResult;
126
+ try {
127
+ result = scan_skills(path.join(REPO_ROOT, SKILLS_ROOT));
128
+ } catch (e) {
129
+ process.stderr.write(`error: ${String(e)}\n`);
130
+ return 1;
131
+ }
132
+
133
+ for (const f of result.findings) {
134
+ process.stdout.write(`❌ ${f.file} ${f.message}\n`);
135
+ }
136
+ if (result.findings.length === 0 && !quiet) {
137
+ process.stdout.write(
138
+ `✅ token-budget discipline: ${String(result.richCount)} rich of ${String(result.scanned)} skills within the ${String(RICH_RATIO_CAP * 100)} % cap; every rich skill justifies itself\n`,
139
+ );
140
+ }
141
+ // gate-coverage contract (src/config/gate-coverage.yml): files inspected.
142
+ process.stdout.write(`scanned: ${String(result.scanned)}\n`);
143
+ return result.findings.length > 0 ? 2 : 0;
144
+ }
145
+
146
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
147
+ process.exit(main());
148
+ }