@event4u/agent-config 16.4.0 → 16.5.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 (77) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +40 -191
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/design.md +1 -1
  7. package/dist/agent-src/guidelines/design-antipatterns.md +1 -1
  8. package/dist/agent-src/rules/token-budget-discipline.md +2 -2
  9. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +2 -0
  10. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  11. package/dist/agent-src/skills/canvas-design/SKILL.md +4 -2
  12. package/dist/agent-src/skills/design-intelligence/references/integration-mapping.md +13 -10
  13. package/dist/agent-src/skills/fe-design/references/design-patterns.md +49 -2
  14. package/dist/agent-src/skills/frontend-render-security/SKILL.md +9 -0
  15. package/dist/agent-src/skills/iconography/SKILL.md +4 -2
  16. package/dist/agent-src/skills/image-provider-routing/SKILL.md +16 -5
  17. package/dist/agent-src/skills/logo-generation/SKILL.md +12 -8
  18. package/dist/agent-src/skills/svg-authoring/SKILL.md +318 -0
  19. package/dist/agent-src/skills/wireframe/SKILL.md +5 -2
  20. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  21. package/dist/cli/commands/uiRender.js +201 -4
  22. package/dist/cli/commands/uiRenderAsset.js +1308 -0
  23. package/dist/cli/commands/uiRenderAssetCompare.js +752 -0
  24. package/dist/cli/commands/uiRenderAssetGrid.js +265 -0
  25. package/dist/cli/commands/uiRenderAssetGrounds.js +323 -0
  26. package/dist/cli/commands/uiRenderAssetIsolation.js +85 -0
  27. package/dist/cli/commands/uiRenderAssetTypes.js +145 -0
  28. package/dist/cli/main.js +47 -1
  29. package/dist/cli/registry.js +1 -1
  30. package/dist/cli-delegate/{chunk-MSUL5NYP.js → chunk-4DBG5K7M.js} +1 -1
  31. package/dist/cli-delegate/{chunk-AED2VQGM.js → chunk-TMWYUOK4.js} +10 -1
  32. package/dist/cli-delegate/cmd_conformance.js +395 -214
  33. package/dist/cli-delegate/cmd_handoff.js +2 -2
  34. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  35. package/dist/discovery/deprecation-report.md +1 -1
  36. package/dist/discovery/discovery-manifest.json +47 -22
  37. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  38. package/dist/discovery/discovery-manifest.summary.md +6 -6
  39. package/dist/discovery/dormancy-report.md +1 -1
  40. package/dist/discovery/orphan-report.md +1 -1
  41. package/dist/discovery/packs.json +19 -15
  42. package/dist/discovery/trust-report.md +2 -2
  43. package/dist/discovery/workspaces.json +13 -9
  44. package/dist/hooks/dispatch.js +1073 -808
  45. package/dist/hooks/dispatch.sha256 +1 -1
  46. package/dist/hooks/svg_rules.chunk.cjs +1626 -0
  47. package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -0
  48. package/dist/mcp/registry-manifest.json +3 -3
  49. package/dist/mcp/server.json +2 -2
  50. package/dist/mcp/server.mjs +931 -735
  51. package/dist/scripts/_lib/scan_scope.js +105 -0
  52. package/dist/scripts/_lib/svg_dom.js +284 -0
  53. package/dist/scripts/_lib/svg_geometry.js +477 -0
  54. package/dist/scripts/_lib/svg_motion.js +179 -0
  55. package/dist/scripts/_lib/svg_rules.js +1337 -0
  56. package/dist/scripts/_lib/svg_urls.js +67 -0
  57. package/dist/scripts/lint_svg_asset.js +324 -0
  58. package/docs/guidelines/design-antipatterns.md +1 -1
  59. package/package.json +4 -3
  60. package/src/config/gate-violation-baselines.json +3 -3
  61. package/src/config/routing-coverage-seed.json +9 -2
  62. package/src/scripts/_lib/svg_dom.ts +318 -0
  63. package/src/scripts/_lib/svg_geometry.ts +480 -0
  64. package/src/scripts/_lib/svg_motion.ts +208 -0
  65. package/src/scripts/_lib/svg_rules.ts +1453 -0
  66. package/src/scripts/_lib/svg_urls.ts +72 -0
  67. package/src/scripts/_lib/verification_command.ts +59 -0
  68. package/src/scripts/_lib/verify_clause.ts +27 -17
  69. package/src/scripts/hooks/block_speaking_inbox_dir.ts +16 -1
  70. package/src/scripts/hooks/design_pass_hook.ts +157 -3
  71. package/src/scripts/hooks/svg_obligation.ts +497 -0
  72. package/src/scripts/hooks/svg_rules_loader.ts +133 -0
  73. package/src/scripts/hooks/turn_end_gate_hook.ts +5 -3
  74. package/src/scripts/lint_consolidation_lineage.ts +6 -3
  75. package/src/scripts/lint_design_quality.ts +60 -12
  76. package/src/scripts/lint_motion_authority_drift.ts +27 -0
  77. package/src/scripts/lint_svg_asset.ts +365 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * uiRenderAssetTypes — the asset profile's declared vocabulary.
3
+ *
4
+ * Its own module so that the profile and its geometry comparison can both read
5
+ * these without importing each other: the profile calls the comparison, the
6
+ * comparison needs the classes and the tolerance shape, and a direct import
7
+ * either way round is a cycle.
8
+ *
9
+ * Every constant here was pre-registered in step 0.3 of
10
+ * `road-to-svg-with-a-witness` — before any checker existed — so a threshold
11
+ * could not be chosen to fit what a rule already reported.
12
+ */
13
+ import * as path from 'node:path';
14
+ // ---------------------------------------------------------------------------
15
+ // Declared constants — every one of them pre-registered in step 0.3
16
+ // ---------------------------------------------------------------------------
17
+ export const ASSET_CLASSES = ['icon', 'mark', 'illustration', 'diagram', 'animated'];
18
+ /**
19
+ * Per class, never global. A file is loose BELOW its class threshold.
20
+ * Overridden by a `fill_ratio_thresholds` block in `--thresholds <file>`.
21
+ */
22
+ export const DEFAULT_FILL_RATIO_THRESHOLDS = {
23
+ icon: 0.3,
24
+ mark: 0.45,
25
+ illustration: 0.4,
26
+ diagram: 0.35,
27
+ animated: 0.35,
28
+ };
29
+ /** Step 2.6's tolerances. Overridden by `geometry_tolerances` in `--thresholds`. */
30
+ export const DEFAULT_GEOMETRY_TOLERANCES = {
31
+ icon: { silhouette_iou_min: 0.98, max_boundary_distance_units: 1 },
32
+ mark: { silhouette_iou_min: 0.98, max_boundary_distance_units: 2 },
33
+ illustration: { silhouette_iou_min: 0.96, max_boundary_distance_units: 3 },
34
+ diagram: { silhouette_iou_min: 0.97, max_boundary_distance_units: 2 },
35
+ animated: { silhouette_iou_min: 0.97, max_boundary_distance_units: 2 },
36
+ };
37
+ /**
38
+ * Used ONLY when no `tokens.json` resolves. The manifest records
39
+ * `source: "fallback"` whenever these are used, because a reader cannot
40
+ * otherwise tell a project's own background from this module's guess.
41
+ */
42
+ export const FALLBACK_BACKGROUNDS = { light: '#ffffff', dark: '#111111' };
43
+ /** The four paths the brand resolver searches, in its order. First hit wins. */
44
+ export const BRAND_TOKEN_PATHS = [
45
+ 'tokens.json',
46
+ 'assets/tokens.json',
47
+ 'resources/tokens.json',
48
+ path.join('agents', 'settings', 'brand', 'tokens.json'),
49
+ ];
50
+ /** Icon sizes are the three the incumbent sets ship at. Other classes: 1x and 2x. */
51
+ export const ICON_SIZES = [16, 24, 48];
52
+ /**
53
+ * A `mark` is captured here too — step 4.3 of
54
+ * `road-to-svg-from-a-live-session`.
55
+ *
56
+ * A review sent an accepted mark back because its face turned to mush at
57
+ * 32 px, and a simplified small-size variant was built. Nothing in the profile
58
+ * produced a capture at those sizes, so the only way to know was to look at
59
+ * something that did not exist. 16 and 32 are the two the review named.
60
+ */
61
+ export const MARK_SMALL_SIZES = [16, 32];
62
+ /**
63
+ * Below this, a draw-on animation is not reported. The planted row reads
64
+ * 0.283 (a 300-unit dash on a 215-unit path) and its twin reads 0.0, so the
65
+ * band between them is wide; 0.05 is inside it with room on both sides.
66
+ */
67
+ export const DRAW_ON_DEAD_TIME_THRESHOLD = 0.05;
68
+ /** A channel at or above this, with alpha 1, counts as near-white paint. */
69
+ export const NEAR_WHITE_CHANNEL = 237;
70
+ /**
71
+ * The synthetic host document. Fulfilled by the route handler at a URL inside
72
+ * the asset's OWN directory, so a relative `href` inside the asset resolves
73
+ * exactly as it would in place — without this module ever writing into the
74
+ * directory it is reading.
75
+ */
76
+ export const HOST_BASENAME = '__agent-config-asset-host__.html';
77
+ /** Schemes a page may reach. Everything else is aborted and counted. */
78
+ export const ALLOWED_SCHEMES = ['file:', 'data:', 'blob:', 'about:'];
79
+ /**
80
+ * How a shape declares that a gap in the silhouette is DELIBERATE.
81
+ *
82
+ * Step 4.1. A ring has a hole in the middle and the ground shows through it on
83
+ * purpose; without a way to say so, every ring reads as a seam. By attribute
84
+ * rather than by geometry, because "is this gap intended" is a question only
85
+ * the author can answer.
86
+ */
87
+ export const HOLE_ATTRIBUTE = 'data-hole';
88
+ /**
89
+ * The bleed share above which `geometry/background-bleed-inside-silhouette`
90
+ * fires, pre-registered in `fixtures/svg-assets/README.md` before the reading
91
+ * was written.
92
+ *
93
+ * A seam is a hairline: one or two pixels wide along a shared edge. The
94
+ * overlap twin — the same two shapes overlapping by one unit — reads 0. The
95
+ * threshold sits between them with room on both sides.
96
+ *
97
+ * IT DOES MOVE WITH THE RENDER SIZE, and this doc used to claim it does not.
98
+ * Finding 7 of the third completion review. A share is scale-free only when
99
+ * both terms scale together: a seam whose width is a fraction of a USER UNIT
100
+ * grows with the capture and its share is stable, but one that is an
101
+ * anti-aliasing artefact stays one or two DEVICE pixels wide at every size, so
102
+ * its count grows with the perimeter while the denominator grows with the
103
+ * area — the share falls roughly as 1/width. The planted fixture is the second
104
+ * kind (a ring of inner radius 20 against a disc of radius 20), so this number
105
+ * is pre-registered against the capture sizes THIS PROFILE TAKES, which top
106
+ * out at 2x the intrinsic width. A caller rendering the same file at several
107
+ * thousand pixels would read a share below the threshold on a file that still
108
+ * has the seam.
109
+ *
110
+ * Not re-derived here: fixing it means making the reading a function of the
111
+ * seam's width in user units rather than of its pixel count, which is a
112
+ * different measurement and a larger change than a remediation should take.
113
+ * Stated so a reader is not told the opposite.
114
+ */
115
+ export const BLEED_SHARE_THRESHOLD = 0.002;
116
+ /**
117
+ * Above this share of the registered source's painted pixels lying OUTSIDE the
118
+ * subject, `geometry/foreign-content-in-frame` fires.
119
+ *
120
+ * Finding 14 of this change's completion review: it was an inline `0.02` beside
121
+ * two named, documented, pre-registered thresholds. 2 % is the band an
122
+ * anti-aliased outline can occupy on a small mark without anything foreign
123
+ * being in the frame — it is a NOISE FLOOR, not a measured quality line, and
124
+ * saying so is the difference between a number a reader can argue with and one
125
+ * they cannot find.
126
+ */
127
+ export const FOREIGN_CONTENT_SHARE_THRESHOLD = 0.02;
128
+ /** Below this contrast ratio against its ground, a painted pixel is hard to see. */
129
+ export const MIN_CONTRAST_RATIO = 3;
130
+ /**
131
+ * The share of painted pixels below {@link MIN_CONTRAST_RATIO} above which
132
+ * `accessibility/low-contrast-on-background` fires.
133
+ *
134
+ * Half the mark, not a few anti-aliased edge pixels: an edge blends into its
135
+ * ground by construction, and a rule that fired on that would fire on every
136
+ * file. Pre-registered with the bleed threshold above.
137
+ */
138
+ export const LOW_CONTRAST_SHARE_THRESHOLD = 0.5;
139
+ /**
140
+ * The square sample grid both the profile and the comparison rasterise into.
141
+ * One constant because a comparison taken at a different resolution than the
142
+ * reading it is compared against is not a comparison.
143
+ */
144
+ export const SAMPLE_RES = 256;
145
+ //# sourceMappingURL=uiRenderAssetTypes.js.map
package/dist/cli/main.js CHANGED
@@ -23,6 +23,7 @@ import { runDoctorShell } from './commands/doctorShell.js';
23
23
  import { runRtkDetect } from './commands/rtkDetect.js';
24
24
  import { runUiAudit } from './commands/uiAudit.js';
25
25
  import { runUiRender } from './commands/uiRender.js';
26
+ import { parseRegistration } from './commands/uiRenderAssetCompare.js';
26
27
  import { runUiServe } from './commands/uiServe.js';
27
28
  import { shouldInitLaunchGui, buildInitGuiOptions, buildProjectInitDelegation, findInitGuiConflict, withoutGuiFlag } from './initRouting.js';
28
29
  import { maybePrintFirstRunNotice } from './firstRunNotice.js';
@@ -125,8 +126,53 @@ async function main(rawArgv) {
125
126
  .option('--json', 'Print the manifest on stdout as well as writing it')
126
127
  .option('--project-root <path>', 'Override the project root')
127
128
  .option('--slug <name>', 'Override the output directory name')
129
+ .option('--profile <name>', 'page (default) or asset — a single SVG, per class, light and dark')
130
+ .option('--class <name>', 'Asset class: icon | mark | illustration | diagram | animated')
131
+ .option('--delivery <mode>', 'Delivery mode: inline | document | img | css-bg')
132
+ .option('--thresholds <file>', 'JSON carrying fill_ratio_thresholds / geometry_tolerances')
133
+ .option('--icon-set <paths>', 'Comma-separated incumbent icon SVGs, read for their own grid')
134
+ .option('--compare <file>', 'Second render of the same frame to compare against')
135
+ .option('--registration <spec>', 'Raster source region as x,y,w,h[@scale]')
128
136
  .action(async (target, opts) => {
129
- process.exitCode = await runUiRender({ target, ...opts });
137
+ // Validated, not cast. A cast let `--class Icon` through as an
138
+ // AssetClass that matches no threshold key, so
139
+ // `fill_ratio_threshold` came out `undefined`,
140
+ // `structure/loose-viewbox` could never fire, and the key
141
+ // vanished from the manifest — a silent downgrade of a reading
142
+ // to nothing. `lint_svg_asset` validates the same two
143
+ // vocabularies and exits 1; so does this.
144
+ const ASSET_CLASS_NAMES = ['icon', 'mark', 'illustration', 'diagram', 'animated'];
145
+ const DELIVERY_NAMES = ['inline', 'document', 'img', 'css-bg'];
146
+ if (opts.class !== undefined && !ASSET_CLASS_NAMES.includes(opts.class)) {
147
+ process.stderr.write(`[ui:render] unknown --class "${opts.class}"; expected one of ${ASSET_CLASS_NAMES.join(', ')}\n`);
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+ if (opts.delivery !== undefined && !DELIVERY_NAMES.includes(opts.delivery)) {
152
+ process.stderr.write(`[ui:render] unknown --delivery "${opts.delivery}"; expected one of ${DELIVERY_NAMES.join(', ')}\n`);
153
+ process.exitCode = 1;
154
+ return;
155
+ }
156
+ if (opts.profile !== undefined && opts.profile !== 'page' && opts.profile !== 'asset') {
157
+ process.stderr.write(`[ui:render] unknown --profile "${opts.profile}"; expected page or asset\n`);
158
+ process.exitCode = 1;
159
+ return;
160
+ }
161
+ process.exitCode = await runUiRender({
162
+ target,
163
+ ...(opts.json === undefined ? {} : { json: opts.json }),
164
+ ...(opts.projectRoot === undefined ? {} : { projectRoot: opts.projectRoot }),
165
+ ...(opts.slug === undefined ? {} : { slug: opts.slug }),
166
+ ...(opts.profile === 'asset' ? { profile: 'asset' } : {}),
167
+ ...(opts.class === undefined ? {} : { assetClass: opts.class }),
168
+ ...(opts.delivery === undefined ? {} : { delivery: opts.delivery }),
169
+ ...(opts.thresholds === undefined ? {} : { thresholds: opts.thresholds }),
170
+ ...(opts.iconSet === undefined ? {} : { iconSet: opts.iconSet.split(',').map((s) => s.trim()) }),
171
+ ...(opts.compare === undefined ? {} : { compareTo: opts.compare }),
172
+ ...(parseRegistration(opts.registration) === null
173
+ ? {}
174
+ : { registration: parseRegistration(opts.registration) }),
175
+ });
130
176
  });
131
177
  program
132
178
  .command('ui:serve')
@@ -37,7 +37,7 @@ export const REGISTRY = [
37
37
  { name: 'rtk:detect', disposition: 'native', synopsis: 'rtk (Rust Token Killer) presence + identity readout — contract: docs/contracts/rtk-detection.md.' },
38
38
  { name: 'ui:serve', disposition: 'native', synopsis: 'Start the local UI server.' },
39
39
  { name: 'ui:audit', disposition: 'native', synopsis: 'Inventory a UI tree into agents/runtime/state/ui-audit.json (Class A; the artefact ui-audit-gate reads).' },
40
- { name: 'ui:render', disposition: 'native', synopsis: 'Headless capture at desktop / 375px / 320px into agents/runtime/state/render/ (Class A; no process survives).' },
40
+ { name: 'ui:render', disposition: 'native', synopsis: 'Headless capture at desktop / 375px / 320px, or --profile asset for one SVG per class on a light and a dark background, into agents/runtime/state/render/ (Class A; no process survives).' },
41
41
  { name: 'config', disposition: 'native', synopsis: 'Open the configuration GUI (global by default; --project for the project surface).' },
42
42
  { name: 'settings', disposition: 'native', synopsis: 'Open the local Settings GUI (alias of config).' },
43
43
  { name: 'install', disposition: 'native', synopsis: 'Open the install wizard (UI server, lands on Step 1 / AI tools).' },
@@ -3,7 +3,7 @@ import {
3
3
  pruneAgedRefusalState,
4
4
  readSessionCounts,
5
5
  statePathFor
6
- } from "./chunk-AED2VQGM.js";
6
+ } from "./chunk-TMWYUOK4.js";
7
7
  import {
8
8
  current_branch,
9
9
  git_common_dir,
@@ -562,6 +562,8 @@ function segmentVerifies(rawWords) {
562
562
  case "node":
563
563
  case "deno":
564
564
  return rest.some((a) => a === "test" || a.startsWith("--test"));
565
+ case "agent-config":
566
+ return false;
565
567
  case "scripts-run": {
566
568
  const script = bareName(arg1);
567
569
  return /^(check|lint|verify|validate)[-_]/.test(script);
@@ -579,6 +581,12 @@ var _WIDE_CANDIDATE_RE = /\b(test|tests|vitest|jest|pytest|phpunit|pest|tsc|esli
579
581
  function mightBeVerification(command) {
580
582
  return _WIDE_CANDIDATE_RE.test(command);
581
583
  }
584
+ function isAssetRenderCommand(command) {
585
+ return /\bui:render\b/.test(command) && /--profile[= ]\s*asset\b/.test(command);
586
+ }
587
+ function isVerificationAttempt(command) {
588
+ return isVerificationCommand(command) || isAssetRenderCommand(command);
589
+ }
582
590
 
583
591
  // src/scripts/_lib/touched_file_quality.ts
584
592
  import { spawnSync } from "node:child_process";
@@ -2753,7 +2761,8 @@ function pruneAgedRefusalState(workspaceRoot, opts = {}) {
2753
2761
  }
2754
2762
 
2755
2763
  export {
2756
- isVerificationCommand,
2764
+ isAssetRenderCommand,
2765
+ isVerificationAttempt,
2757
2766
  readRunEvidence,
2758
2767
  hasRedThenGreen,
2759
2768
  describeRecordFinding,