youiyoux 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,26 +1,36 @@
1
1
  # youiyoux
2
2
 
3
- A shareable report on any repo's UI, with no setup:
3
+ **Your agent rebuilds components you already have. youiyoux catches it.**
4
+
5
+ UI context and verification for coding agents: it tells the agent what your repo already has before
6
+ it writes UI, then checks what it wrote.
4
7
 
5
8
  ```sh
6
- npx youiyoux # in a repo: scan it, write the report
7
- npx youiyoux path/to/repo
9
+ npx youiyoux # scan this repo
10
+ npx youiyoux path/to/repo # or another one; --out <dir> writes elsewhere
8
11
  ```
9
12
 
10
- It prints five plain-English lines and writes three files to the repo (or `--out <dir>`), and nothing else:
13
+ No config, no account. You get:
14
+
15
+ - `youiyoux-report.html`: near-duplicate components and which to keep, hardcoded values your theme already has, off-library imports, and the top fixes with their next steps. One offline page.
16
+ - `youiyoux-card.png`: a 1200×630 card with the headline numbers.
17
+ - `youiyoux-summary.md`: paste it into a PR or issue.
18
+
19
+ ## For your agent
11
20
 
12
- | File | What |
13
- | --- | --- |
14
- | `youiyoux-report.html` | One self-contained page (no network requests, light and dark, readable on a phone): projects (one section per workspace package with UI files), UI libraries, the component inventory, near-duplicate groups, hardcoded values a theme token already holds, off-library imports and the top fixes, each with a concrete next step |
15
- | `youiyoux-card.png` | A 1200×630 share card with the repo's name and the headline numbers |
16
- | `youiyoux-summary.md` | A short summary for a README or pull request |
21
+ ```sh
22
+ npx youiyoux agents install # rule in AGENTS.md + CLAUDE.md, MCP server for Claude Code + Codex
23
+ npx youiyoux hooks install # check after each Claude Code edit, and at git commit
24
+ ```
17
25
 
18
- **Rendered looks.** When a Chromium is installed (the Playwright headless shell, or `YOUI_CHROMIUM`), the most-used components are drawn with the project's own code and CSS and embedded. Otherwise the report says how: `npx youiyoux --render` asks before downloading the headless shell (~100 MB, once); `--yes` allows it without asking. Everything else works without a browser.
26
+ - `ui_find_component` (MCP): before writing a component, the existing one with its import, props and a real usage.
27
+ - `npx youiyoux check --diff`: after UI edits, what the change adds, each with its fix.
28
+ - `ui_render` (MCP) or `npx youiyoux render <file>`: screenshots light and dark, accessibility issues, a diff against base.
19
29
 
20
- **Safe to share by default.** Paths are relative to the repo. Includes relative paths, component names, class lists, counts and rendered images when available. Captions and fixes omit literal prop values and text content; source lines require `--include-code`. Home paths, usernames, environment or `.env` values, and credentials in URLs are removed. `--include-code` adds source lines and full look captions (keys and tokens in it still removed).
30
+ ## Privacy
21
31
 
22
- **Set up youiyoux for your agent:** `npx youiyoux agents install` tells Claude Code and Codex to look up the project's existing components before writing new ones. Every other `youiyoux` command runs the same way (`npx youiyoux check --diff`), The `youi` bin remains a silent compatibility alias.
32
+ Runs locally; nothing is uploaded, no telemetry. The report includes relative paths, component names, class lists, counts and rendered images when available. No source lines unless `--include-code`; home paths, usernames, env values and credentials are stripped. Rendered looks need a headless Chromium (`--render` offers to download it, ~100 MB, once); specimen images are cached in `~/.cache/youiyoux/specimens`.
23
33
 
24
- Node 20 or later. Nothing is uploaded, there is no telemetry and no account.
34
+ Node 20 or later. The `youi` bin is a silent alias.
25
35
 
26
- Specimen images are cached outside the repo in `~/.cache/youiyoux/specimens` (`XDG_CACHE_HOME` overrides `~/.cache`; `YOUI_SPECIMEN_CACHE` overrides the specimen directory). Rendered images show the component as rendered, including visible labels.
36
+ Docs, agent reference and source: [github.com/ap9000/youiyoux](https://github.com/ap9000/youiyoux)
@@ -4,7 +4,7 @@ import {
4
4
  findFiles,
5
5
  require_dist,
6
6
  writeFileAtomic
7
- } from "./chunk-ZLRFD5JI.js";
7
+ } from "./chunk-C3TSTYP7.js";
8
8
  import {
9
9
  __toESM
10
10
  } from "./chunk-E4HNK7VF.js";
@@ -27331,7 +27331,7 @@ var STAGE_MOVES = [
27331
27331
  function canMove(from, to, actor) {
27332
27332
  return STAGE_MOVES.some((move) => move.from === from && move.to === to && move.by.includes(actor));
27333
27333
  }
27334
- var MCP_TOOLS = ["system_search", "system_get_component", "system_get_tokens", "system_get_rules", "system_where_used", "system_screen_bom", "system_check", "system_plan", "library_search", "library_request", "discover_search", "discover_show", "index_where_used", "index_swap_impact", "index_rule_covers", "ui_find_component", "ui_render"];
27334
+ var MCP_TOOLS = ["system_search", "system_get_component", "system_get_tokens", "system_get_rules", "system_where_used", "system_screen_bom", "system_check", "system_plan", "library_search", "library_request", "discover_search", "discover_show", "index_where_used", "index_swap_impact", "index_rule_covers", "ui_find_component", "ui_render", "requests_list", "request_reply", "request_addressed"];
27335
27335
  var LIBRARY_KINDS = ["component", "token", "pattern"];
27336
27336
  var LIBRARY_ID_PATTERN = /^lib:([a-z][a-z0-9-]*)\/(component|token|pattern)\/([a-z0-9][a-z0-9.\-]*)$/;
27337
27337
  var LibraryId = external_exports.string().regex(LIBRARY_ID_PATTERN, "expected lib:<source>/<kind>/<name>");
@@ -27406,6 +27406,55 @@ async function loadLibrary(root) {
27406
27406
  return { entries };
27407
27407
  }
27408
27408
 
27409
+ // ../core/src/requests.ts
27410
+ var IsoTime2 = external_exports.string().datetime({ offset: true });
27411
+ var REQUEST_ID = /^r-[0-9a-f]{10}$/;
27412
+ var REQUEST_STATUSES = ["open", "addressed", "closed"];
27413
+ var RequestAuthor = external_exports.object({ kind: external_exports.enum(["person", "agent"]), name: external_exports.string().min(1).max(100) });
27414
+ var Box = external_exports.object({ x: external_exports.number(), y: external_exports.number(), width: external_exports.number().nonnegative(), height: external_exports.number().nonnegative() });
27415
+ var Size = external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() });
27416
+ var RequestTarget = external_exports.object({
27417
+ /** The route as the usage map names it (`/settings`, `*` for the app shell). */
27418
+ route: external_exports.string().min(1).max(300),
27419
+ /** here: this one, on this screen; element: every place the element is used. */
27420
+ scope: external_exports.enum(["here", "element"]),
27421
+ /** The component's name as it rendered (`Button`). */
27422
+ name: external_exports.string().min(1).max(200),
27423
+ /** The System element it is, or the one a lookalike stands in for. */
27424
+ element: ElementId.optional(),
27425
+ lookalike: external_exports.boolean().optional(),
27426
+ /** Project-relative, and the line that rendered it, when the capture found them. */
27427
+ file: external_exports.string().min(1).max(500).optional(),
27428
+ line: external_exports.number().int().positive().optional(),
27429
+ box: Box.optional(),
27430
+ page: Size.optional()
27431
+ });
27432
+ var RequestEntry = external_exports.object({
27433
+ author: RequestAuthor,
27434
+ at: IsoTime2,
27435
+ body: external_exports.string().max(4e3),
27436
+ /** A status change this entry made, if any. */
27437
+ status: external_exports.enum(REQUEST_STATUSES).optional()
27438
+ });
27439
+ var RequestDoc = external_exports.object({
27440
+ $schema: external_exports.string().optional(),
27441
+ schema: external_exports.literal("youi.request/v1"),
27442
+ id: external_exports.string().regex(REQUEST_ID, "expected r-<10 hex>"),
27443
+ /** The project id from youi.project.json. */
27444
+ project: external_exports.string().min(1).max(200),
27445
+ /** comment: a note; change: something to do. */
27446
+ kind: external_exports.enum(["comment", "change"]),
27447
+ status: external_exports.enum(REQUEST_STATUSES),
27448
+ body: external_exports.string().min(1).max(4e3),
27449
+ author: RequestAuthor,
27450
+ createdAt: IsoTime2,
27451
+ updatedAt: IsoTime2,
27452
+ target: RequestTarget,
27453
+ /** The screen as it was when this was filed (`<id>.before.webp` beside it), to compare with after a change. */
27454
+ before: external_exports.string().regex(/^r-[0-9a-f]{10}\.before\.webp$/).optional(),
27455
+ thread: external_exports.array(RequestEntry).max(500)
27456
+ });
27457
+
27409
27458
  // ../core/src/tokens.ts
27410
27459
  var TOKEN_ALIAS = /^\{([^{}]+)\}$/;
27411
27460
  var ALIAS_MESSAGE = "expected an alias like {color.brand}";
@@ -27617,7 +27666,7 @@ function normalizeRelPath(path) {
27617
27666
  return posix2.normalize(path.replace(/\\/g, "/")).replace(/^\.\//, "").replace(/\/+$/, "") || ".";
27618
27667
  }
27619
27668
  var RelPath = external_exports.string().min(1).refine((p) => !p.startsWith("/") && !normalizeRelPath(p).split("/").includes(".."), "expected a path relative to its root, without ..");
27620
- var IsoTime2 = external_exports.string().datetime({ offset: true });
27669
+ var IsoTime3 = external_exports.string().datetime({ offset: true });
27621
27670
  var SystemConfig = external_exports.object({
27622
27671
  id: external_exports.string().regex(/^[a-z][a-z0-9-]*$/, { error: ({ input: input2 }) => safeId(input2) === null ? `Invalid system id ${JSON.stringify(input2)}: use a plain name without ".." or path separators` : `Invalid system id ${JSON.stringify(input2)}: use lowercase letters, digits and hyphens, starting with a letter` }),
27623
27672
  name: external_exports.string().min(1),
@@ -27875,7 +27924,7 @@ var ScanReport = external_exports.object({
27875
27924
  /** Files checked from supplied text (unsaved edits, candidate code) rather than disk. */
27876
27925
  overrides: external_exports.array(external_exports.string())
27877
27926
  }).optional(),
27878
- generatedAt: IsoTime2,
27927
+ generatedAt: IsoTime3,
27879
27928
  durationMs: external_exports.number(),
27880
27929
  status: external_exports.enum(["complete", "partial"]),
27881
27930
  coverage: external_exports.object({
@@ -27918,7 +27967,7 @@ var Baseline = external_exports.object({
27918
27967
  $schema: external_exports.string().optional(),
27919
27968
  schema: external_exports.literal("youi.baseline/v1"),
27920
27969
  project: external_exports.string(),
27921
- recordedAt: IsoTime2,
27970
+ recordedAt: IsoTime3,
27922
27971
  identity: CheckIdentity,
27923
27972
  totals: external_exports.object({ errors: external_exports.number().int(), warnings: external_exports.number().int() }),
27924
27973
  entries: external_exports.array(BaselineEntry)
@@ -27940,7 +27989,7 @@ var LockFile = external_exports.object({
27940
27989
  system: external_exports.string(),
27941
27990
  systemVersion: SemVer,
27942
27991
  sourceCommit: external_exports.string().nullable(),
27943
- syncedAt: IsoTime2,
27992
+ syncedAt: IsoTime3,
27944
27993
  files: external_exports.record(external_exports.string(), LockEntry)
27945
27994
  });
27946
27995
  var INVENTORY_ROLES = ["button", "link-as-button", "input", "card", "badge", "dialog", "tabs"];
@@ -28092,7 +28141,7 @@ var InventoryReport = external_exports.object({
28092
28141
  $schema: external_exports.string().optional(),
28093
28142
  schema: external_exports.literal("youi.inventory/v1"),
28094
28143
  scanner: external_exports.string(),
28095
- generatedAt: IsoTime2,
28144
+ generatedAt: IsoTime3,
28096
28145
  durationMs: external_exports.number(),
28097
28146
  /** Two looks share a family only when every dimension is within these (px; weight in units) of every other look's. */
28098
28147
  tolerance: external_exports.object({ height: external_exports.number(), padding: external_exports.number(), radius: external_exports.number(), fontSize: external_exports.number(), fontWeight: external_exports.number() }),
@@ -28126,7 +28175,8 @@ var PUBLISHED_SCHEMAS = {
28126
28175
  "youi.baseline.schema.json": Baseline,
28127
28176
  "youi.inventory.schema.json": InventoryReport,
28128
28177
  "youi.detect.schema.json": DetectReport,
28129
- "youi.tokens.schema.json": TokenDocument
28178
+ "youi.tokens.schema.json": TokenDocument,
28179
+ "youi.request.schema.json": RequestDoc
28130
28180
  };
28131
28181
  function normalizeProjectConfig(config2) {
28132
28182
  const n = normalizeRelPath;
@@ -28263,6 +28313,12 @@ function executionLabel(execution) {
28263
28313
  }
28264
28314
  }
28265
28315
 
28316
+ // ../core/src/licence.ts
28317
+ function copyleft(spdx) {
28318
+ const strong = (part) => part.split(/\s+(?:AND|WITH)\s+/).some((id) => /^A?GPL-/.test(id.replace(/[()]/g, "").trim()));
28319
+ return spdx.split(/\s+OR\s+/).every(strong);
28320
+ }
28321
+
28266
28322
  export {
28267
28323
  require_dist,
28268
28324
  clone,
@@ -28323,6 +28379,11 @@ export {
28323
28379
  LibraryEntry,
28324
28380
  LIBRARY_DIR,
28325
28381
  loadLibrary,
28382
+ copyleft,
28383
+ REQUEST_ID,
28384
+ REQUEST_STATUSES,
28385
+ RequestTarget,
28386
+ RequestDoc,
28326
28387
  TOKEN_ALIAS,
28327
28388
  CSS_SAFE_NAME,
28328
28389
  aliasesIn,