@event4u/agent-config 10.3.0 → 11.0.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 (107) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +147 -0
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze.md +2 -1
  5. package/dist/agent-src/commands/council/debate.md +13 -4
  6. package/dist/agent-src/commands/council/default.md +26 -11
  7. package/dist/agent-src/commands/council.md +1 -1
  8. package/dist/agent-src/commands/design-system/capture.md +44 -0
  9. package/dist/agent-src/commands/design-system/generate.md +75 -0
  10. package/dist/agent-src/commands/design-system/import.md +63 -0
  11. package/dist/agent-src/commands/design-system.md +66 -0
  12. package/dist/agent-src/commands/pr/create.md +51 -26
  13. package/dist/agent-src/commands/worktree/create.md +5 -3
  14. package/dist/agent-src/rules/settings-ask-protocol.md +14 -9
  15. package/dist/agent-src/skills/ai-council/SKILL.md +24 -6
  16. package/dist/agent-src/skills/corpus-grounding/SKILL.md +12 -1
  17. package/dist/agent-src/skills/corpus-grounding/scripts/decision_engine.ts +215 -7
  18. package/dist/agent-src/skills/corpus-grounding/scripts/ground.ts +39 -1
  19. package/dist/agent-src/skills/design-intelligence/ATTRIBUTION.md +19 -2
  20. package/dist/agent-src/skills/design-intelligence/data/manifest.json +36 -1
  21. package/dist/agent-src/skills/design-intelligence/data/motion.csv +17 -0
  22. package/dist/agent-src/skills/design-system-capture/SKILL.md +9 -0
  23. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +70 -0
  24. package/dist/agent-src/skills/git-workflow/SKILL.md +9 -3
  25. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +9 -6
  26. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +25 -21
  27. package/dist/agent-src/templates/agent-settings.md +0 -1
  28. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  29. package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +4 -1
  30. package/dist/cli-delegate/{chunk-BV3WR67D.js → chunk-55WZN5VF.js} +3 -6
  31. package/dist/cli-delegate/{chunk-X3VOARZD.js → chunk-L565YFXH.js} +3 -3
  32. package/dist/cli-delegate/{chunk-JMQZ7MM5.js → chunk-MNWRDMR5.js} +1 -1
  33. package/dist/cli-delegate/{chunk-IR3IVRVC.js → chunk-NLP54U3J.js} +2 -1
  34. package/dist/cli-delegate/{chunk-FV34EGEX.js → chunk-NN4KW4HZ.js} +1 -1
  35. package/dist/cli-delegate/{chunk-6ENSXSBW.js → chunk-PPQO4NGR.js} +1 -1
  36. package/dist/cli-delegate/chunk-RLN73PR5.js +157 -0
  37. package/dist/cli-delegate/{chunk-6LOPHJLD.js → chunk-RYNADUFG.js} +1 -1
  38. package/dist/cli-delegate/{chunk-I5EAFRII.js → chunk-ZPSXJTLI.js} +2 -154
  39. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  40. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  41. package/dist/cli-delegate/cmd_conformance.js +673 -215
  42. package/dist/cli-delegate/cmd_doctor.js +2 -2
  43. package/dist/cli-delegate/cmd_explain.js +2 -2
  44. package/dist/cli-delegate/cmd_export.js +4 -4
  45. package/dist/cli-delegate/cmd_handoff.js +10 -8
  46. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  47. package/dist/cli-delegate/cmd_migrate.js +2 -2
  48. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  49. package/dist/cli-delegate/cmd_prune.js +4 -4
  50. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  51. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  52. package/dist/cli-delegate/cmd_session_recycle.js +6 -4
  53. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  54. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  55. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  56. package/dist/cli-delegate/cmd_sync.js +4 -4
  57. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  58. package/dist/cli-delegate/cmd_update.js +1 -1
  59. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  60. package/dist/cli-delegate/cmd_validate.js +4 -4
  61. package/dist/cli-delegate/cmd_versions.js +1 -1
  62. package/dist/discovery/deprecation-report.md +1 -1
  63. package/dist/discovery/discovery-manifest.json +127 -22
  64. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  65. package/dist/discovery/discovery-manifest.summary.md +3 -3
  66. package/dist/discovery/dormancy-report.md +1 -1
  67. package/dist/discovery/orphan-report.md +1 -1
  68. package/dist/discovery/packs.json +9 -5
  69. package/dist/discovery/trust-report.md +2 -2
  70. package/dist/discovery/workspaces.json +8 -4
  71. package/dist/hooks/dispatch.js +994 -399
  72. package/dist/install/install.mjs +5 -7
  73. package/dist/mcp/registry-manifest.json +2 -2
  74. package/dist/mcp/server.json +2 -2
  75. package/dist/mcp/server.mjs +1104 -593
  76. package/dist/scripts/_lib/agent_settings.js +8 -0
  77. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  78. package/dist/server/schemas/settings.js +3 -4
  79. package/dist/server/schemas/settings.js.map +1 -1
  80. package/dist/ui/assets/{index-5fXOHoVh.js → index-B0aMJnuz.js} +2 -2
  81. package/dist/ui/assets/{index-5fXOHoVh.js.map → index-B0aMJnuz.js.map} +1 -1
  82. package/dist/ui/index.html +1 -1
  83. package/docs/contracts/settings-classes.md +12 -9
  84. package/package.json +1 -1
  85. package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +4 -1
  86. package/src/config/agent-settings.template.yml +15 -18
  87. package/src/config/gate-coverage.yml +33 -2
  88. package/src/config/gate-violation-baselines.json +2 -2
  89. package/src/config/pack-size-budget.json +3 -2
  90. package/src/scripts/_lib/agent_settings.ts +8 -0
  91. package/src/scripts/_lib/design_system_import.ts +987 -0
  92. package/src/scripts/check_branch_freshness.ts +238 -6
  93. package/src/scripts/design_system_import.ts +264 -0
  94. package/src/scripts/external_sources_denylist.json +7 -2
  95. package/src/scripts/hook_manifest.yaml +71 -2
  96. package/src/scripts/hooks/concern_registry.ts +4 -0
  97. package/src/scripts/hooks/dispatch_hook.ts +10 -0
  98. package/src/scripts/hooks/host_semantics.ts +2 -0
  99. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +212 -0
  100. package/src/scripts/hooks/subagent_ledger_hook.ts +723 -0
  101. package/src/scripts/hooks/turn_end_gate_hook.ts +39 -2
  102. package/src/scripts/lint_hook_manifest.ts +2 -0
  103. package/src/scripts/lint_rule_skill_pack_reach.ts +194 -13
  104. package/src/scripts/session_register_hook.ts +120 -10
  105. package/src/server/schemas/settings.ts +3 -6
  106. package/tests/fixtures/hooks/subagent_start.json +7 -0
  107. package/tests/fixtures/hooks/subagent_stop.json +8 -0
@@ -2,7 +2,7 @@
2
2
  "upstream": {
3
3
  "sha": "b7e3af80f6e331f6fb456667b82b12cade7c9d35",
4
4
  "repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill",
5
- "last_checked": "2026-06-07",
5
+ "last_checked": "2026-08-13",
6
6
  "last_eval": {
7
7
  "date": "2026-06-16",
8
8
  "model": "claude-sonnet-4-5",
@@ -257,6 +257,29 @@
257
257
  "Severity"
258
258
  ],
259
259
  "max_results": 3
260
+ },
261
+ "gsap": {
262
+ "file": "motion.csv",
263
+ "search_cols": [
264
+ "Category",
265
+ "Intensity Tier",
266
+ "Keywords",
267
+ "Trigger"
268
+ ],
269
+ "output_cols": [
270
+ "Category",
271
+ "Intensity Tier",
272
+ "Keywords",
273
+ "Trigger",
274
+ "Duration",
275
+ "Easing",
276
+ "GSAP Snippet",
277
+ "Framework Notes",
278
+ "Do",
279
+ "Don't",
280
+ "Performance Notes"
281
+ ],
282
+ "max_results": 3
260
283
  }
261
284
  },
262
285
  "detect": {
@@ -454,6 +477,18 @@
454
477
  "form",
455
478
  "input type",
456
479
  "preconnect"
480
+ ],
481
+ "gsap": [
482
+ "motion",
483
+ "animation",
484
+ "animate",
485
+ "transition",
486
+ "easing",
487
+ "gsap",
488
+ "hover effect",
489
+ "scroll reveal",
490
+ "parallax",
491
+ "stagger"
457
492
  ]
458
493
  },
459
494
  "reasoning": {
@@ -0,0 +1,17 @@
1
+ No,Category,Intensity Tier,Keywords,Trigger,Duration,Easing,GSAP Snippet,Framework Notes,Do,Don't,Performance Notes
2
+ 1,Hover Micro-interaction,Subtle,"hover, button, opacity, lift, press feedback",hover,150-200ms,power1.out,"gsap.to(el, { y: -1, opacity: 0.9, duration: 0.15, ease: 'power1.out' });",Bind on mouseenter/mouseleave; in React wrap in a ref + useEffect (or onMouseEnter/onMouseLeave props directly calling gsap.to),Keep displacement under 2px so it reads as feedback not motion,Don't animate layout-affecting props (width/height/margin) on hover,Runs on transform/opacity only so it stays on the compositor thread
3
+ 2,Hover Micro-interaction,Standard,"hover, card, scale, tilt, cursor feedback",hover,200-300ms,power2.out,"gsap.to(el, { y: -4, scale: 1.02, boxShadow: '0 12px 24px rgba(0,0,0,0.12)', duration: 0.25, ease: 'power2.out' });","Use gsap.quickTo(el, 'y') for cards with many hover targets to avoid re-creating tweens every event",Pair with a matching mouseleave tween that reverses the same properties,Don't leave the hover state stuck if the pointer leaves fast; always attach the reverse tween,quickTo() avoids GC churn on lists with 20+ hoverable cards
4
+ 3,Hover Micro-interaction,Complex,"hover, magnetic, cursor follow, 3d tilt",hover + mousemove,300-500ms,"elastic.out(1,0.4)","const xTo = gsap.quickTo(el, 'x', { duration: 0.4, ease: 'elastic.out(1,0.4)' }); const yTo = gsap.quickTo(el, 'y', { duration: 0.4, ease: 'elastic.out(1,0.4)' }); el.addEventListener('mousemove', (e) => { const r = el.getBoundingClientRect(); xTo((e.clientX - r.left - r.width/2) * 0.3); yTo((e.clientY - r.top - r.height/2) * 0.3); });",Debounce is not needed since quickTo interpolates; remove listeners on component unmount in React/Vue to avoid leaks,Clamp the pull strength (e.g. * 0.3) so the element never fully leaves its hit box,Don't apply magnetic effect to more than 1-2 focal elements per screen; it becomes noisy,Use will-change: transform on the target element for smoother compositing
5
+ 4,Scroll Reveal,Subtle,"scroll, fade in, reveal, on view",scroll (viewport enter),300-400ms,power1.out,"gsap.from(el, { opacity: 0, y: 12, duration: 0.35, ease: 'power1.out', scrollTrigger: { trigger: el, start: 'top 90%', toggleActions: 'play none none reverse' } });",Requires the ScrollTrigger plugin registered once via gsap.registerPlugin(ScrollTrigger),"Keep the y offset small (8-16px) so it reads as a fade, not a slide",Don't reveal below-the-fold content needed for SEO/crawlers as invisible-by-default without a no-JS fallback,toggleActions 'play none none reverse' avoids re-triggering on every scroll direction change
6
+ 5,Scroll Reveal,Standard,"scroll, slide up, staggered section, reveal",scroll (viewport enter),400-600ms,power2.out,"gsap.from(el.children, { opacity: 0, y: 24, duration: 0.5, stagger: 0.08, ease: 'power2.out', scrollTrigger: { trigger: el, start: 'top 85%' } });","In React use useGSAP(() => {...}, { scope: containerRef }) from @gsap/react to auto-cleanup on unmount",Scope the ScrollTrigger to the section container so it doesn't re-scan the whole page,Don't stagger more than ~8 children; beyond that the last items feel laggy,Set scroller/markers: false in production; markers is dev-only
7
+ 6,Scroll Reveal,Complex,"scroll, pin, scrub, storytelling, scrollytelling",scroll (continuous scrub),tied to scroll position,none (scrub-driven),"gsap.timeline({ scrollTrigger: { trigger: section, start: 'top top', end: '+=150%', scrub: 1, pin: true } }).from('.headline', { opacity: 0, y: 40 }).to('.bg-layer', { yPercent: -20 }, '<');",Pinning needs the section to have deterministic height; recalc ScrollTrigger.refresh() after images/fonts load,Use scrub: true or a small number (0.5-1.5) instead of instant jumps so it feels tied to the scrollbar,Don't pin more than 1-2 sections per page; excessive pinning fights native scroll feel and hurts mobile UX,"Pinning forces layout reflow; test on mid-tier mobile devices, not just desktop"
8
+ 7,Stagger List,Subtle,"list, stagger, cards, grid entrance",load or scroll,250-350ms,power1.out,"gsap.from('.list-item', { opacity: 0, y: 8, duration: 0.3, stagger: 0.03 });",Select items with a stable class/data-attribute (not array index) so re-renders in React don't break targeting,Keep per-item stagger delay small (0.02-0.04s) for lists longer than 10 items,Don't stagger by more than 0.1s per item on long lists; total reveal time becomes sluggish,"For virtualized lists, only animate items currently mounted in the DOM"
9
+ 8,Stagger List,Standard,"grid, bento, cards, staggered scale",load or scroll,300-450ms,back.out(1.4),"gsap.from('.grid-item', { opacity: 0, scale: 0.92, y: 16, duration: 0.4, stagger: { each: 0.06, from: 'start', grid: 'auto' }, ease: 'back.out(1.4)' });",grid: 'auto' lets GSAP infer rows/columns from a CSS grid layout for a natural wave stagger,Combine with from: 'center' for a bento-grid layout to draw the eye inward first,Don't use back.out on dense data tables; the overshoot reads as sloppy on informational UI,Group DOM writes; avoid interleaving layout reads (getBoundingClientRect) between staggered tweens
10
+ 9,Stagger List,Complex,"stagger, wave, text reveal, split text",load or scroll,400-700ms,expo.out,"const split = new SplitText(headline, { type: 'chars' }); gsap.from(split.chars, { opacity: 0, y: 20, rotateX: -40, duration: 0.6, stagger: 0.015, ease: 'expo.out' });",SplitText is a GSAP Club/paid plugin; confirm license before shipping and provide a plain fade fallback if unavailable,Revert SplitText on unmount/cleanup (split.revert()) to restore original text nodes for accessibility tools,Don't split-animate long paragraphs; reserve for short headlines (under ~8 words),Splitting text creates one element per character; keep it to headline-length copy only for DOM size
11
+ 10,Page Transition,Subtle,"route change, fade, page transition",route change,200-300ms,power1.inOut,"gsap.to(main, { opacity: 0, duration: 0.2, onComplete: () => { navigate(); gsap.fromTo(main, { opacity: 0 }, { opacity: 1, duration: 0.2 }); } });","Pair with the router's transition hooks (Next.js App Router transitions, React Router's useNavigate, Vue Router's beforeEach/afterEach)",Preload the destination route's critical assets before the exit tween finishes,Don't block navigation on animation; cap exit duration at ~250ms so the app never feels unresponsive,Exit animation should always resolve faster than entrance (asymmetric timing) so back/forward feels snappy
12
+ 11,Page Transition,Standard,"route change, slide, overlay wipe",route change,400-600ms,power2.inOut,"const tl = gsap.timeline(); tl.to('.transition-overlay', { yPercent: 0, duration: 0.4, ease: 'power2.inOut' }).call(navigate).to('.transition-overlay', { yPercent: -100, duration: 0.4, ease: 'power2.inOut', delay: 0.1 });",Keep the overlay element mounted at the layout root (outside the page component) so it survives the route swap,Show a lightweight loading indicator if the destination route's data fetch outlasts the overlay,Don't tie the overlay's reveal directly to data-fetch completion without a max-wait timeout; a slow API stalls the whole transition,Prefer CSS transform (yPercent) over top/left to keep the overlay animation on the compositor thread
13
+ 12,Page Transition,Complex,"shared element, morph, hero transition",route change,500-800ms,expo.inOut,"const state = Flip.getState('.hero-image'); navigate(); Flip.from(state, { duration: 0.6, ease: 'expo.inOut', absolute: true, zIndex: 100 });",Requires the GSAP Flip plugin; the 'from' and 'to' route must render the same element with a shared data-flip-id,Verify the shared element exists in both DOM states before calling Flip.from to avoid a silent no-op,Don't use shared-element transitions across more than one element pair per navigation; compounding Flips are hard to time correctly,Flip recalculates layout (FLIP technique) so test on low-end devices for jank
14
+ 13,Parallax Scroll,Subtle,"parallax, background, depth, scroll speed",scroll (continuous),tied to scroll position,linear (scrub),"gsap.to('.bg-layer', { yPercent: 10, ease: 'none', scrollTrigger: { trigger: section, scrub: true } });","Apply parallax to background/decorative layers only, never to text or interactive controls",Keep the yPercent delta small (5-15) so foreground and background never desync distractingly,Don't parallax body copy; it hurts reading comfort and can trigger motion sickness,will-change: transform on the parallax layer only; remove it after scroll settles to free GPU memory
15
+ 14,Parallax Scroll,Standard,"multi-layer parallax, depth, hero background",scroll (continuous),tied to scroll position,linear (scrub),"gsap.utils.toArray('.parallax-layer').forEach((layer, i) => { gsap.to(layer, { yPercent: (i + 1) * -8, ease: 'none', scrollTrigger: { trigger: layer.parentElement, scrub: 0.5 } }); });",Layer count beyond 3-4 has diminishing visual return and multiplies scroll-listener cost,"Vary speed per layer (background slowest, foreground fastest) to sell the depth illusion",Don't let parallax layers overflow their container; clip with overflow: hidden on the wrapper,Batch all layers under one ScrollTrigger container where possible instead of one per layer
16
+ 15,Loading / Skeleton,Subtle,"loading, skeleton, shimmer, pulse",on mount / async wait,1200-1600ms loop,sine.inOut,"gsap.to('.skeleton', { backgroundPosition: '200% 0', duration: 1.4, ease: 'sine.inOut', repeat: -1 });",Kill the loop tween (tween.kill()) as soon as real content mounts to avoid orphaned repeating animations,Use a CSS gradient background-position sweep rather than opacity pulsing; reads as 'loading' more clearly,Don't run more than one shimmer loop per skeleton group; sync them under one timeline so the wave reads as a single unit,repeat: -1 tweens are cheap but must be explicitly killed on unmount or they leak in SPA route changes
17
+ 16,Loading / Skeleton,Standard,"progress, spinner, morphing loader",on mount / async wait,800-1200ms loop,power1.inOut,"gsap.timeline({ repeat: -1 }).to('.loader-dot', { y: -8, duration: 0.4, stagger: { each: 0.15, yoyo: true, repeat: 1 } });",Wrap the whole loop timeline in useGSAP with { revertOnUpdate: false } in React so it isn't rebuilt every render,Cap total loop duration under ~1.5s so long waits don't feel like the UI froze on a single beat,Don't use elaborate loaders for sub-300ms waits; they flash and feel worse than no indicator,Pause the timeline (tl.pause()) when the loading tab/view is not visible to save CPU on background tabs
@@ -202,6 +202,15 @@ auto-installer (out of scope). Full schema is lazy-loaded from
202
202
  [`references/design-system-json.md`](references/design-system-json.md) — read it
203
203
  only when an import is requested.
204
204
 
205
+ **The supply path is real, and it is one command.** Where an extractor's output
206
+ is not already in this shape, run it through the three-lane adapter first —
207
+ `/design-system:import <file>`, which accepts a native artifact, a DTCG token
208
+ file, or an extraction tool's raw JSON and emits the contract. Lanes and
209
+ documented producers:
210
+ [`references/design-system-json.md`](references/design-system-json.md)
211
+ § Extractor compatibility. The adapter is offline and pure — it does not change
212
+ what this skill owns.
213
+
205
214
  **Import procedure:**
206
215
 
207
216
  1. Read `design-system.json`; reject it if `source` (kind + ref + captured_at)
@@ -71,3 +71,73 @@ brand wins). Precedence on import: registered brand tokens > confirmed
71
71
 
72
72
  The package **owns this contract**; it does **not** ship the crawler, the
73
73
  Playwright runtime, or a font-bundler.
74
+
75
+ ## Extractor compatibility — which crawler, and how its output gets here
76
+
77
+ The contract above says what this skill reads. This section says how a real
78
+ tool's output becomes that shape, so the answer to *"which crawler?"* lives in
79
+ the contract rather than in somebody's memory.
80
+
81
+ `src/scripts/design_system_import.ts` is a **pure, offline file transform** with
82
+ three input lanes. It reads a file and writes the contract shape to stdout — no
83
+ network, no browser, no crawl. That is the lock restated as code: a transform
84
+ that fetched would quietly become the crawler this package does not ship.
85
+
86
+ | Lane | Input | What it does |
87
+ |---|---|---|
88
+ | `native` | an existing `design-system.json` | Validates `source`, carries every other key verbatim. Past provenance the validation is **report-only** — a key whose shape contradicts the contract is flagged and kept, never dropped, because the import is a proposal a human reads. |
89
+ | `dtcg` | a W3C DTCG token file (`{$value, $type}` leaves) | Buckets by `$type`, so it works on any authoring tool's layering — **with two stated path exceptions**: `dimension` / `number` is genuinely ambiguous in DTCG (spacing, radius and font size share it), so the path breaks that tie, and a path segment named `dark` files a colour under the dark theme. Both are inferences and both are reported in the notes. Resolves `{alias.references}` to their values. Tokens with no contract bucket land in `_meta.unmapped` — which is why `component.button.paddingX` lands there rather than under spacing. |
90
+ | `dembrandt` | an extraction tool's raw JSON | Matches the documented top-level key names and accepts a small set of shapes per bucket. Motion durations/easings become the `motion` block; per-context profiles, hover deltas, WCAG results and breakpoints are **observation** and land in `_meta`. |
91
+
92
+ ```bash
93
+ # The command is the supported entry point:
94
+ /design-system:import <file>
95
+
96
+ # Or call the transform directly, from an installed package:
97
+ npx tsx node_modules/@event4u/agent-config/src/scripts/design_system_import.ts <file> \
98
+ [--lane native|dtcg|dembrandt] \
99
+ [--source-kind url|repo|dir --source-ref <ref>] [--captured-at <ISO>] \
100
+ [--format json|summary]
101
+ ```
102
+
103
+ **Documented producers.** Two extraction tools are known to emit input this
104
+ adapter consumes, and both are **user-installed and user-connected** — the
105
+ package ships the adapter, the instructions, and the validation, never the tool:
106
+
107
+ - **dembrandt** (MIT, npm) — the richest single source: computed-DOM tokens,
108
+ automatic motion extraction (duration scale, easing curves), component
109
+ observations, WCAG pairs, and a stdio MCP server. Feeds the `dembrandt` lane
110
+ directly, or the `dtcg` lane via its `--dtcg` export.
111
+ - **designlang** (MIT) — DTCG in primitive/semantic/composite layers plus
112
+ interaction states. Feeds the `dtcg` lane. Its own repo-writing feature is not
113
+ invoked; this package owns its projection.
114
+
115
+ A third, **extract-design-system**, emits plain W3C `tokens.json` and feeds the
116
+ same `dtcg` lane. Any other tool that can export DTCG works without a new lane.
117
+
118
+ **Provenance is mandatory on every lane, and its origin is recorded.** DTCG
119
+ carries no `source` block by construction, so the caller supplies one; the
120
+ result then carries `source._meta.provenance_origin: "caller"` rather than
121
+ `"input"`, so a reader can always tell an extracted provenance from an asserted
122
+ one. Neither one present is a rejection, not a default — you cannot confirm what
123
+ you cannot trace.
124
+
125
+ **A lane is never forced.** Where a real sample cannot be mapped without
126
+ inventing values, the adapter emits it as `_meta` observation and says so in a
127
+ note. An import that lands mostly under `_meta` is the designed degradation, not
128
+ a failure — it means the tool's shape moved, and the values are still in front
129
+ of the human instead of silently coerced into tokens.
130
+
131
+ **Parked, not adopted — runtime drift detection.** One documented producer also
132
+ ships a drift gate: `--compare <baseline>` against a captured baseline, with
133
+ distinct exit codes (0 clean · 1 drift · 2 usage · 67 threshold) and a
134
+ machine-readable `drift` key carrying per-token `changes[]`. That is a
135
+ *design-quality CI* capability, not an import one, and nothing in this package
136
+ asks for it today — recorded here as a candidate so the next reader finds it
137
+ already assessed, and taken up only if a design-quality roadmap asks for runtime
138
+ drift detection.
139
+
140
+ The compatibility matrix is committed as tests, not prose:
141
+ `tests/scripts/fixtures/design-system-import/` holds one input/expected pair per
142
+ lane, and that directory's README states which sample is a real capture and
143
+ which is derived from a tool's published output surface.
@@ -52,9 +52,15 @@ gh pr view <number> --json number,state,mergeStateStatus,mergedAt,baseRefName
52
52
  - **Before merging** → re-fetch and re-read `state` + `mergeStateStatus` in the
53
53
  **same turn**; never merge on a status seen earlier in the conversation.
54
54
  - **"Based on main" / "current"** → prove it with
55
- `git rev-list --count HEAD..origin/main` (after `git fetch`); non-zero ⇒ the
56
- branch is behind and is **not** current — merge `main` in before opening a PR
57
- (see [`/create-pr`](../../commands/pr/create.md) § 1b).
55
+ `npx tsx node_modules/@event4u/agent-config/src/scripts/check_branch_freshness.ts`;
56
+ exit `1` ⇒ the branch is behind and is **not** current — merge the base in,
57
+ regenerate the derived files, then open the PR (see
58
+ [`/create-pr`](../../commands/pr/create.md) § 1b).
59
+ Prefer it over `git rev-list --count HEAD..origin/main`, which is wrong twice
60
+ over: it pins `main` as the base for a branch whose PR may target something
61
+ else, and it reads the local tracking ref — a fetch from earlier in the
62
+ session, which is memory rather than a check. The gate asks the remote and
63
+ resolves the base from the open PR.
58
64
 
59
65
  ## Conventions
60
66
 
@@ -302,14 +302,17 @@ prefer the cheaper one (`do-and-judge` < `do-and-judge-two-stage` <
302
302
  `do-in-steps` < `do-in-parallel` < `do-competitively` <
303
303
  `judge-with-debate` < `do-in-worktrees`).
304
304
 
305
- **Mode 6 (`do-in-worktrees`) is gated by `worktrees.mode`** from
306
- `.agent-settings.yml` (default: `ask`). Resolve before picking:
305
+ **Mode 6 (`do-in-worktrees`) is instruction-only** (ADR-229). There is no
306
+ setting to resolve — `worktrees.mode` was deleted:
307
307
 
308
- | `worktrees.mode` | Mode 6 |
308
+ | Situation | Mode 6 |
309
309
  |---|---|
310
- | `ask` | Eligible. `using-git-worktrees` will run the per-creation permission ask. |
311
- | `on` | Eligible. Per-creation ask suppressed. |
312
- | `off` | **Not eligible.** Fall back to mode 3 (`do-in-steps`) — same step-by-step chain, in-place on the current branch. Unless the user **explicitly asked this turn** for a worktree chain, in which case proceed with mode 6 and acknowledge the override per [`using-git-worktrees § Pre-flight`](../using-git-worktrees/SKILL.md). |
310
+ | The user asked for a worktree chain in the chat ("do this in a worktree", "use mode 6") | Eligible. Proceed via [`using-git-worktrees`](../using-git-worktrees/SKILL.md); the request is the permission, so there is no further ask. |
311
+ | Anything else | **Not eligible**, however well the chain shape fits. Fall back to mode 3 (`do-in-steps`) — the same step-by-step chain, in place on the current branch. Do not offer mode 6 as an option. |
312
+
313
+ Because mode 6 is unreachable unprompted, it is effectively off the
314
+ cheapness ladder above unless the user named it; read that ordering as
315
+ covering modes 1–8 in the default case.
313
316
 
314
317
  ### 4. Dispatch
315
318
 
@@ -48,30 +48,34 @@ work and makes it impossible to tell what you broke.
48
48
 
49
49
  ## Procedure
50
50
 
51
- ### 0. Pre-flight — read `worktrees.mode`
51
+ ### 0. Pre-flight — instruction-only, no setting to read
52
52
 
53
- Before anything else, read `worktrees.mode` from `.agent-settings.yml`
54
- (default: `ask`). The setting is a **mechanical layer on top of**
55
- `scope-control`'s permission gate — it narrows, never widens.
53
+ ```
54
+ NEVER CREATE A WORKTREE THE USER DID NOT ASK FOR.
55
+ THERE IS NO SETTING. THE ONLY TRIGGER IS THE USER SAYING SO IN THE CHAT.
56
+ ```
57
+
58
+ There is nothing to read: `worktrees.mode` was deleted (ADR-229). Creation
59
+ is instruction-only and hardcoded, so the decision is never the agent's.
56
60
 
57
- | `worktrees.mode` | Behaviour |
61
+ | Situation | Behaviour |
58
62
  |---|---|
59
- | `ask` | Status quo. Continue to step 1; `scope-control` permission gate applies for every worktree creation. |
60
- | `on` | Standing permission. Skip the per-creation permission ask; continue to step 1. Iron-Law gates (ignore-check, clean baseline) still apply. |
61
- | `off` | No autonomous worktree creation. **Refuse** unless the user explicitly asked **this turn** for a worktree ("do this in a worktree", "use mode 6", "spawn a worktree for X"). |
62
-
63
- **Off, no explicit request** → stop. Tell the user the setting is `off`,
64
- suggest the in-place alternative (`subagent-orchestration` mode 3
65
- `do-in-steps`, or just stay on the current branch). Do not re-ask on
66
- the same task.
67
-
68
- **Off, with explicit request this turn** → acknowledge once
69
- ("`worktrees.mode` is `off`; running this on your explicit request
70
- for this task") and continue to step 1. The override is for this one
71
- task — it does not flip the setting.
72
-
73
- The setting only suppresses **unprompted** usage. The tool stays
74
- available when the user wants it.
63
+ | The user asked for a worktree **in the chat** — "do this in a worktree", "use mode 6", "spawn a worktree for X", or the same in another language | Continue to step 1. No permission question: the request **is** the permission. |
64
+ | Anything else, however well the shape would fit | **Do not create one.** Continue in place. |
65
+
66
+ **No explicit request** → do not ask, do not offer, do not mention it. Use
67
+ the in-place path (`subagent-orchestration` mode 3 `do-in-steps`, or just
68
+ stay on the current branch) and say nothing about worktrees. Proposing one
69
+ unprompted is the failure this rule exists to stop — it puts a decision the
70
+ user did not raise in front of them, and the answer is nearly always no.
71
+
72
+ This suppresses **unprompted** usage only. The tool stays fully available
73
+ the moment the user wants it, with no confirmation loop in the way: an
74
+ explicit request goes straight to step 1.
75
+
76
+ The Iron-Law gates below are unchanged and still run on every
77
+ explicitly-requested worktree — ignore-safety check (step 3) and clean
78
+ baseline (step 5). Instruction-only removes the *choice*, never the checks.
75
79
 
76
80
  ### 1. Inspect current state
77
81
 
@@ -575,7 +575,6 @@ the canonical narrative lives in
575
575
  | `subagents.implementer_model` | model alias or empty | _(empty)_ | Model for implementer subagents. Empty = same tier as session model. See [subagent-configuration](../contexts/subagent-configuration.md). |
576
576
  | `subagents.judge_model` | model alias or empty | _(empty)_ | Model for judge subagents. Empty = one tier above implementer (opus if sonnet, sonnet if haiku). |
577
577
  | `subagents.max_parallel` | integer | `3` | Maximum parallel subagent invocations. `1` serializes. |
578
- | `worktrees.mode` | `off`, `on`, `ask` | `ask` | Controls autonomous `git worktree` usage. `off` = skill refuses unless the user explicitly asks for a worktree that turn (then it runs); `subagent-orchestration` mode 6 falls back to mode 3. `on` = standing permission (skill skips the per-creation ask; ignore-check and clean-baseline gates still apply). `ask` = status quo — `scope-control` permission gate runs every time. |
579
578
  | `roles.default_role` | `""`, `developer`, `reviewer`, `tester`, `po`, `incident`, `planner` | _(empty)_ | Role the agent defaults to at the start of a session. Lives in the PROJECT settings (`agent-project-settings.example.yml` § roles), not in the personal template. See [`role-contracts`](../docs/guidelines/agent-infra/role-contracts.md). |
580
579
  | `roles.active_role` | same as `default_role` | _(empty)_ | Role currently active; set by `/mode <name>`, cleared by `/mode none`. Enables the `role-mode-adherence` rule. |
581
580
  | `personas.override` | list of persona ids | `[]` | Developer-local override of the team default lens cast (not in the shipped personal template — add the block when needed). Empty = inherit `personas.default` from `.agent-project-settings.yml`. See [`layered-settings`](../docs/guidelines/agent-infra/layered-settings.md). |
@@ -39,7 +39,7 @@ schema_version: 1
39
39
  # CI guard: a release bump of `package.json` must update this value
40
40
  # in lockstep — see scripts/check_template_pin_drift.ts (road-to-
41
41
  # portable-runtime-and-update-check P3.3).
42
- agent_config_version: "10.3.0"
42
+ agent_config_version: "11.0.0"
43
43
 
44
44
  # --- Project identity ---
45
45
  project:
@@ -345,7 +345,10 @@ function _halt_provided_without_contract(
345
345
  '> 1. Proceed — port it with those five losses on the record; `apply` ' +
346
346
  'still has to report what it honoured, translated, and flagged',
347
347
  '> 2. Supply a `design-system.json` — its token values are then ' +
348
- 'honoured verbatim instead of re-derived',
348
+ 'honoured verbatim instead of re-derived. Already have an ' +
349
+ "extractor's output in another shape? `/design-system:import " +
350
+ '<file>` maps a DTCG token file or an extraction tool\'s raw JSON ' +
351
+ 'into this contract offline.',
349
352
  '> 3. Abort — drop this UI request',
350
353
  '',
351
354
  '**Recommendation: 2 — Supply the contract** — it is the only option ' +
@@ -4055,7 +4055,6 @@ var accessStyle = external_exports.enum(["getters_setters", "get_attribute", "ma
4055
4055
  var chatFreq = external_exports.enum(["per_turn", "per_phase", "per_tool"]);
4056
4056
  var qualityCadence = external_exports.enum(["end_of_roadmap", "per_phase", "per_step"]);
4057
4057
  var regenCadence = external_exports.enum(["per_step", "every_5_steps", "phase_boundary"]);
4058
- var worktreeMode = external_exports.enum(["off", "on", "ask"]);
4059
4058
  var fidelityMode = external_exports.enum(["strict", "structural", "hard-floor"]);
4060
4059
  var crossSourceMode = external_exports.enum(["on", "auto", "off"]);
4061
4060
  var richSkillsMode = external_exports.enum(["on", "ask", "off"]);
@@ -4375,11 +4374,9 @@ var settingsSchema = external_exports.object({
4375
4374
  "Opt-in adversarial-verification-council mode (subagent-orchestration Mode 9, ADR-122). off (default) = never runs; ask = offer it on an explicit high-risk change; on = auto-run on high-risk changes. Advisory only \u2014 a panel of distinct-model skeptics red-teams a real change for defect FINDING coverage and NEVER auto-gates it (Hard Floor). Stays default-off until the adversarial-council-finding-coverage claim is backed."
4376
4375
  )
4377
4376
  }),
4378
- worktrees: external_exports.object({
4379
- mode: worktreeMode.default("ask").describe(
4380
- "When the agent considers a parallel `git worktree` for risky / large work. ask (default) = surface a numbered option and wait. on = spawn worktrees autonomously. off = never use worktrees, edit in place."
4381
- )
4382
- }),
4377
+ // `worktrees.mode` was DELETED (ADR-229). Worktree creation is
4378
+ // instruction-only and hardcoded; there is nothing left to configure. A
4379
+ // leftover key is ignored with one deprecation line via REMOVED_KEYS.
4383
4380
  ai_team: external_exports.object({
4384
4381
  model: external_exports.string().default("auto").describe(
4385
4382
  "Model handed to the codex CLI. 'auto' (default) = pass no --model flag so the CLI's own default applies \u2014 tracks the subscription's current strongest model instead of pinning a stale ID. Any other value passes through verbatim as `--model <value>`."
@@ -2,10 +2,10 @@ import { createRequire as __acCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  ZodFirstPartyTypeKind,
4
4
  settingsSchema
5
- } from "./chunk-BV3WR67D.js";
5
+ } from "./chunk-55WZN5VF.js";
6
6
  import {
7
7
  main
8
- } from "./chunk-6ENSXSBW.js";
8
+ } from "./chunk-PPQO4NGR.js";
9
9
  import {
10
10
  RULE_SOURCE_REL
11
11
  } from "./chunk-BKO2AZ7Z.js";
@@ -48,7 +48,7 @@ import {
48
48
  import {
49
49
  find_project_root_with_anchor,
50
50
  load_agent_settings
51
- } from "./chunk-IR3IVRVC.js";
51
+ } from "./chunk-NLP54U3J.js";
52
52
  import {
53
53
  event4u_root,
54
54
  legacy_xdg_root,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-MMJL4TIX.js";
5
5
  import {
6
6
  load_agent_settings
7
- } from "./chunk-IR3IVRVC.js";
7
+ } from "./chunk-NLP54U3J.js";
8
8
 
9
9
  // src/scripts/chat_history.ts
10
10
  import { createHash } from "node:crypto";
@@ -517,7 +517,8 @@ var REMOVED_KEYS = /* @__PURE__ */ new Map([
517
517
  ["chat_history.max_size_kb", "the rotate command takes --max-kb from argv; session-count pruning bounds the file"],
518
518
  ["chat_history.on_overflow", "the overflow mode comes from the rotate command --mode argv"],
519
519
  ["quality.wait_for_remote_ci", "whether to poll follows from the push plus a detectable remote pipeline"],
520
- ["legal_review_prep.consented_at", "the provenance sidecar settings:set writes and consentVerdict reads"]
520
+ ["legal_review_prep.consented_at", "the provenance sidecar settings:set writes and consentVerdict reads"],
521
+ ["worktrees.mode", "the user asking for a worktree in the chat; creation is instruction-only and hardcoded"]
521
522
  ]);
522
523
  var _warnedRemovedKeys = /* @__PURE__ */ new Set();
523
524
  function _readDottedSettingsPath(root, dotted) {
@@ -53,7 +53,7 @@ import {
53
53
  load_agent_settings,
54
54
  project_settings_path,
55
55
  resolve_project_root
56
- } from "./chunk-IR3IVRVC.js";
56
+ } from "./chunk-NLP54U3J.js";
57
57
  import {
58
58
  event4u_root,
59
59
  resolve_with_fallback,
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
2
  import {
3
3
  resolve_project_root
4
- } from "./chunk-IR3IVRVC.js";
4
+ } from "./chunk-NLP54U3J.js";
5
5
  import {
6
6
  resolvePackageRoot
7
7
  } from "./chunk-MCJYCQPF.js";
@@ -0,0 +1,157 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+ import {
3
+ git_common_dir
4
+ } from "./chunk-PZWRPRWP.js";
5
+
6
+ // src/scripts/_lib/envelope_grounding.ts
7
+ import { execFileSync } from "node:child_process";
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+
11
+ // src/scripts/_lib/git_env.ts
12
+ var GIT_DISCOVERY_VARS = [
13
+ "GIT_DIR",
14
+ "GIT_WORK_TREE",
15
+ "GIT_INDEX_FILE",
16
+ "GIT_OBJECT_DIRECTORY",
17
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
18
+ "GIT_COMMON_DIR",
19
+ "GIT_NAMESPACE",
20
+ "GIT_PREFIX"
21
+ ];
22
+ function gitEnv(base = process.env) {
23
+ const env = { ...base };
24
+ for (const key of GIT_DISCOVERY_VARS) {
25
+ delete env[key];
26
+ }
27
+ return env;
28
+ }
29
+
30
+ // src/scripts/_lib/envelope_grounding.ts
31
+ var MAX_FIELD_CHARS = 200;
32
+ var MAX_PATHS = 40;
33
+ function git(root, args) {
34
+ try {
35
+ return execFileSync("git", args, {
36
+ cwd: root,
37
+ env: gitEnv(),
38
+ encoding: "utf-8",
39
+ stdio: ["ignore", "pipe", "ignore"]
40
+ }).trim();
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+ function canonicalizeRepoIdentity(raw) {
46
+ let s = raw.trim();
47
+ s = s.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
48
+ s = s.replace(/^[^/@]+@/, "");
49
+ s = s.replace(/^([^/:]+):(?!\/)/, "$1/");
50
+ s = s.replace(/\/+$/, "");
51
+ s = s.replace(/\.git$/i, "");
52
+ const slash = s.indexOf("/");
53
+ if (slash > 0) {
54
+ s = s.slice(0, slash).toLowerCase() + s.slice(slash);
55
+ } else {
56
+ s = s.toLowerCase();
57
+ }
58
+ return s;
59
+ }
60
+ function collectRepoAnchor(root) {
61
+ const remote = git(root, ["config", "--get", "remote.origin.url"]);
62
+ let identity = null;
63
+ if (remote) {
64
+ identity = canonicalizeRepoIdentity(remote);
65
+ } else {
66
+ const common = git_common_dir(root);
67
+ if (common !== null) {
68
+ try {
69
+ identity = fs.realpathSync(common);
70
+ } catch {
71
+ identity = common;
72
+ }
73
+ }
74
+ }
75
+ return {
76
+ repo_identity: identity ? identity.slice(0, MAX_FIELD_CHARS) : null,
77
+ branch: git(root, ["rev-parse", "--abbrev-ref", "HEAD"]),
78
+ head: git(root, ["rev-parse", "HEAD"])
79
+ };
80
+ }
81
+ var VERIFY_STATE_REL = path.join("agents", "runtime", "state", "verify-before-complete.json");
82
+ function readLastVerify(root) {
83
+ try {
84
+ const raw = fs.readFileSync(path.join(root, VERIFY_STATE_REL), "utf-8");
85
+ const state = JSON.parse(raw);
86
+ const lv = state["last_verification"];
87
+ if (typeof lv !== "object" || lv === null || Array.isArray(lv)) return null;
88
+ const rec = lv;
89
+ const command = typeof rec["command"] === "string" ? rec["command"] : null;
90
+ if (!command) return null;
91
+ const at = typeof rec["at"] === "string" ? rec["at"] : "unknown time";
92
+ return `${command} @ ${at} (no exit status is recorded anywhere)`.slice(0, MAX_FIELD_CHARS);
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+ function collectGrounding(root) {
98
+ const anchor = collectRepoAnchor(root);
99
+ const porcelain = git(root, ["status", "--porcelain"]);
100
+ if (porcelain === null) {
101
+ return { ...anchor, uncommitted_paths: [], status_summary: null, last_verify: readLastVerify(root) };
102
+ }
103
+ const lines = porcelain.split("\n").filter((l) => l.trim().length > 0);
104
+ const paths = lines.map((l) => l.slice(3).trim()).filter((p) => p.length > 0 && p.length <= MAX_FIELD_CHARS).slice(0, MAX_PATHS);
105
+ return {
106
+ ...anchor,
107
+ uncommitted_paths: paths,
108
+ status_summary: lines.length === 0 ? "clean working tree" : `${lines.length} uncommitted path(s)${lines.length > MAX_PATHS ? `, first ${MAX_PATHS} listed` : ""}`,
109
+ last_verify: readLastVerify(root)
110
+ };
111
+ }
112
+ function describeDrift(envelope, actual) {
113
+ if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) return [];
114
+ const e = envelope;
115
+ const drift = [];
116
+ const recordedIdentity = typeof e["repo_identity"] === "string" ? e["repo_identity"] : null;
117
+ if (recordedIdentity && actual.repo_identity && recordedIdentity !== actual.repo_identity) {
118
+ drift.push(
119
+ `IDENTITY DRIFT: this envelope was written in "${recordedIdentity}", you are in "${actual.repo_identity}". Re-verify every path before acting \u2014 same branch name does not mean same working tree.`
120
+ );
121
+ }
122
+ const recordedBranch = typeof e["branch"] === "string" ? e["branch"] : null;
123
+ if (recordedBranch && actual.branch && recordedBranch !== actual.branch) {
124
+ drift.push(
125
+ `BRANCH DRIFT: envelope written on "${recordedBranch}", checkout is on "${actual.branch}".`
126
+ );
127
+ }
128
+ const recordedHead = typeof e["head"] === "string" ? e["head"] : null;
129
+ if (recordedHead && actual.head && recordedHead !== actual.head) {
130
+ drift.push(
131
+ `COMMIT DRIFT: envelope written at ${recordedHead.slice(0, 12)}, HEAD is now ${actual.head.slice(0, 12)} \u2014 re-read anything the envelope quotes.`
132
+ );
133
+ }
134
+ return drift;
135
+ }
136
+
137
+ // src/scripts/_lib/recycle_envelope_paths.ts
138
+ import * as path2 from "node:path";
139
+ var RECYCLE_ENVELOPE_REL = path2.join("agents", "runtime", "state", "recycle-envelope.json");
140
+ var RECYCLE_CONSUMED_REL = path2.join(
141
+ "agents",
142
+ "runtime",
143
+ "state",
144
+ "recycle-envelope.consumed.json"
145
+ );
146
+ var RECYCLE_MAX_AGE_HOURS = 48;
147
+ var RECYCLE_ENVELOPE_MAX_BYTES = 6144;
148
+
149
+ export {
150
+ collectRepoAnchor,
151
+ collectGrounding,
152
+ describeDrift,
153
+ RECYCLE_ENVELOPE_REL,
154
+ RECYCLE_CONSUMED_REL,
155
+ RECYCLE_MAX_AGE_HOURS,
156
+ RECYCLE_ENVELOPE_MAX_BYTES
157
+ };
@@ -2,7 +2,7 @@ import { createRequire as __acCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  DEFAULT_PROJECT_FILE,
4
4
  logger
5
- } from "./chunk-IR3IVRVC.js";
5
+ } from "./chunk-NLP54U3J.js";
6
6
 
7
7
  // src/scripts/config/profiles.ts
8
8
  import * as fs2 from "node:fs";