uidex 0.5.2 → 0.7.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 (39) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/cli.cjs +1542 -1227
  3. package/dist/cli/cli.cjs.map +1 -1
  4. package/dist/cloud/index.cjs +385 -175
  5. package/dist/cloud/index.cjs.map +1 -1
  6. package/dist/cloud/index.d.cts +192 -4
  7. package/dist/cloud/index.d.ts +192 -4
  8. package/dist/cloud/index.js +377 -177
  9. package/dist/cloud/index.js.map +1 -1
  10. package/dist/headless/index.cjs +116 -251
  11. package/dist/headless/index.cjs.map +1 -1
  12. package/dist/headless/index.d.cts +6 -11
  13. package/dist/headless/index.d.ts +6 -11
  14. package/dist/headless/index.js +116 -253
  15. package/dist/headless/index.js.map +1 -1
  16. package/dist/index.cjs +776 -1055
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +152 -160
  19. package/dist/index.d.ts +152 -160
  20. package/dist/index.js +792 -1066
  21. package/dist/index.js.map +1 -1
  22. package/dist/react/index.cjs +801 -1019
  23. package/dist/react/index.cjs.map +1 -1
  24. package/dist/react/index.d.cts +102 -86
  25. package/dist/react/index.d.ts +102 -86
  26. package/dist/react/index.js +821 -1038
  27. package/dist/react/index.js.map +1 -1
  28. package/dist/scan/index.cjs +1550 -1220
  29. package/dist/scan/index.cjs.map +1 -1
  30. package/dist/scan/index.d.cts +210 -12
  31. package/dist/scan/index.d.ts +210 -12
  32. package/dist/scan/index.js +1547 -1219
  33. package/dist/scan/index.js.map +1 -1
  34. package/package.json +22 -21
  35. package/templates/claude/SKILL.md +71 -0
  36. package/templates/claude/references/audit.md +43 -0
  37. package/templates/claude/{rules.md → references/conventions.md} +25 -28
  38. package/templates/claude/audit.md +0 -43
  39. /package/templates/claude/{api.md → references/api.md} +0 -0
@@ -94,6 +94,7 @@ interface ReportRecord {
94
94
  interface Registry {
95
95
  add(entity: Entity): void;
96
96
  get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
97
+ matchPattern<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
97
98
  list<K extends EntityKind>(kind: K): ReadonlyArray<EntityByKind<K>>;
98
99
  query(predicate: (entity: Entity) => boolean): Entity[];
99
100
  byScope(scope: Scope): Entity[];
@@ -101,88 +102,10 @@ interface Registry {
101
102
  setReports(kind: EntityKind, id: string, reports: readonly ReportRecord[]): void;
102
103
  getReports(kind: EntityKind, id: string): readonly ReportRecord[];
103
104
  listReportKeys(): readonly string[];
104
- archiveReport?: (reportId: string, reason?: string) => void | Promise<void>;
105
+ closeReport?: (reportId: string, status?: string) => void | Promise<void>;
105
106
  onReportsChange(cb: () => void): () => void;
106
107
  }
107
108
 
108
- interface UserIdentity {
109
- id: string;
110
- name?: string;
111
- avatar?: string;
112
- }
113
-
114
- type ThemePreference = "light" | "dark" | "auto";
115
- type ResolvedTheme = "light" | "dark";
116
- interface ViewStackEntry {
117
- id: string;
118
- ref: EntityRef | null;
119
- }
120
- interface SessionSnapshot {
121
- hover: EntityRef | null;
122
- selection: EntityRef | null;
123
- stack: ViewStackEntry[];
124
- /** Sticky overlay highlight. Set by "Highlight Element" actions; cleared on Esc. */
125
- pinnedHighlight: EntityRef | null;
126
- inspectorActive: boolean;
127
- theme: ThemePreference;
128
- resolvedTheme: ResolvedTheme;
129
- ingestActive: boolean;
130
- /**
131
- * Identity for the local user. Set once at session creation; gates realtime
132
- * features (cursor labels, presence) and auto-populates report attribution.
133
- */
134
- user: UserIdentity | null;
135
- }
136
- type SessionState = SessionSnapshot;
137
-
138
- interface NavigationState {
139
- stack: ViewStackEntry[];
140
- }
141
- interface NavigationActions {
142
- push(entry: ViewStackEntry): void;
143
- pop(): void;
144
- replace(entry: ViewStackEntry): void;
145
- clear(): void;
146
- reset(stack: ViewStackEntry[]): void;
147
- }
148
- type NavigationStore = StoreApi<NavigationState> & {
149
- nav: NavigationActions;
150
- };
151
-
152
- type SurfaceMode = "idle" | "inspecting" | "palette" | "viewing";
153
- interface ModeSnapshot {
154
- mode: SurfaceMode;
155
- inspectorActive: boolean;
156
- }
157
- interface ModeTransitions {
158
- openPalette(): void;
159
- openInspector(): void;
160
- closeInspector(): void;
161
- toggleInspector(): void;
162
- enterViewing(initialStack: ViewStackEntry[]): void;
163
- dismiss(): void;
164
- popOrTransition(): void;
165
- pushView(entry: ViewStackEntry): void;
166
- }
167
- type ModeStore = StoreApi<ModeSnapshot> & {
168
- transition: ModeTransitions;
169
- };
170
-
171
- interface HighlightActions {
172
- hover(ref: EntityRef, element?: HTMLElement | null, color?: string | null): void;
173
- unhover(): void;
174
- pin(ref?: EntityRef): void;
175
- unpin(): void;
176
- }
177
- type SessionStore = StoreApi<SessionState> & {
178
- readonly nav: NavigationStore;
179
- readonly mode: ModeStore;
180
- readonly highlight: HighlightActions;
181
- select(ref: EntityRef | null): void;
182
- setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
183
- setIngest(active: boolean): void;
184
- };
185
-
186
109
  type ConsoleLevel = "warn" | "error";
187
110
  interface ConsoleEntry {
188
111
  level: ConsoleLevel;
@@ -224,6 +147,12 @@ interface NetworkCapture {
224
147
  clear(): void;
225
148
  }
226
149
 
150
+ interface UserIdentity {
151
+ id: string;
152
+ name?: string;
153
+ avatar?: string;
154
+ }
155
+
227
156
  type RealtimePresenceUser = {
228
157
  userId: string;
229
158
  name: string;
@@ -241,6 +170,8 @@ interface RealtimeChannel {
241
170
  joinRoute(route: string): void;
242
171
  onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
243
172
  onPin(cb: (pin: PinRecord) => void): () => void;
173
+ /** Optional so pre-existing channel stubs keep satisfying the interface. */
174
+ onPinArchived?(cb: (reportId: string) => void): () => void;
244
175
  }
245
176
  interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
246
177
  getConfig(): Promise<IngestConfig>;
@@ -262,8 +193,17 @@ interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegr
262
193
  route?: string;
263
194
  entities?: string;
264
195
  }): Promise<PinRecord[]>;
265
- archive(reportId: string, reason?: ArchiveReason): Promise<void>;
196
+ /**
197
+ * Pin records travel without their screenshot (kept out of `pins.list`
198
+ * so multi-MB frames don't stall the shared socket); the report detail
199
+ * view fetches it lazily through here. Optional for host-provided
200
+ * adapters that inline screenshots on the record instead.
201
+ */
202
+ screenshot?(reportId: string): Promise<string | null>;
203
+ close(reportId: string, reason?: ArchiveReason): Promise<void>;
266
204
  };
205
+ /** Closes the adapter's shared socket. Any later RPC call revives it. */
206
+ dispose?(): void;
267
207
  }
268
208
 
269
209
  interface IngestOptions {
@@ -283,6 +223,74 @@ interface Ingest {
283
223
  readonly network: NetworkCapture | null;
284
224
  }
285
225
 
226
+ type ThemePreference = "light" | "dark" | "auto";
227
+ type ResolvedTheme = "light" | "dark";
228
+ interface ViewStackEntry {
229
+ id: string;
230
+ ref: EntityRef | null;
231
+ }
232
+ interface SessionSnapshot {
233
+ stack: ViewStackEntry[];
234
+ /** Sticky overlay highlight. Set by "Highlight Element" actions; cleared on Esc. */
235
+ pinnedHighlight: EntityRef | null;
236
+ /** Mirrored from the mode store; the surface mode the session is currently in. */
237
+ mode: SurfaceMode;
238
+ theme: ThemePreference;
239
+ resolvedTheme: ResolvedTheme;
240
+ /**
241
+ * Identity for the local user. Set once at session creation; gates realtime
242
+ * features (cursor labels, presence) and auto-populates report attribution.
243
+ */
244
+ user: UserIdentity | null;
245
+ }
246
+ type SessionState = SessionSnapshot;
247
+
248
+ interface NavigationState {
249
+ stack: ViewStackEntry[];
250
+ }
251
+ interface NavigationActions {
252
+ push(entry: ViewStackEntry): void;
253
+ pop(): void;
254
+ clear(): void;
255
+ reset(stack: ViewStackEntry[]): void;
256
+ }
257
+ type NavigationStore = StoreApi<NavigationState> & {
258
+ nav: NavigationActions;
259
+ };
260
+
261
+ type SurfaceMode = "idle" | "inspecting" | "palette" | "viewing";
262
+ interface ModeSnapshot {
263
+ mode: SurfaceMode;
264
+ }
265
+ interface ModeTransitions {
266
+ openPalette(): void;
267
+ openInspector(): void;
268
+ closeInspector(): void;
269
+ toggleInspector(): void;
270
+ enterViewing(initialStack: ViewStackEntry[]): void;
271
+ dismiss(): void;
272
+ popOrTransition(): void;
273
+ pushView(entry: ViewStackEntry): void;
274
+ }
275
+ type ModeStore = StoreApi<ModeSnapshot> & {
276
+ transition: ModeTransitions;
277
+ };
278
+
279
+ interface HighlightActions {
280
+ hover(ref: EntityRef, element?: HTMLElement | null, color?: string | null): void;
281
+ unhover(): void;
282
+ pin(ref?: EntityRef): void;
283
+ unpin(): void;
284
+ }
285
+ type SessionStore = StoreApi<SessionState> & {
286
+ readonly nav: NavigationStore;
287
+ readonly mode: ModeStore;
288
+ readonly highlight: HighlightActions;
289
+ setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
290
+ };
291
+
292
+ type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
293
+
286
294
  interface OverlayShowOptions {
287
295
  label?: string;
288
296
  color?: string;
@@ -293,8 +301,6 @@ interface OverlayShowOptions {
293
301
  backdrop?: boolean;
294
302
  }
295
303
 
296
- type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
297
-
298
304
  interface RouteMatch {
299
305
  view: View;
300
306
  priority: number;
@@ -362,6 +368,8 @@ interface DetailSurface {
362
368
  entityKind: EntityKind;
363
369
  /** Registry lookup failed — renders the "not found" placeholder. */
364
370
  notFound?: EntityRef;
371
+ /** Entity exists in the DOM but not in the registry (gen file). */
372
+ unregistered?: boolean;
365
373
  /** Entity display name, rendered as the heading. */
366
374
  title?: string;
367
375
  subtitle?: DetailSubtitle;
@@ -438,9 +446,16 @@ type DetailSection = {
438
446
  id: "routes";
439
447
  paths: readonly string[];
440
448
  filterable?: boolean;
441
- } | {
449
+ }
450
+ /**
451
+ * `url` renders immediately; `load` fetches lazily (cloud pins travel
452
+ * without their screenshot) and the section stays hidden until — and
453
+ * unless — the promise resolves with a data URL.
454
+ */
455
+ | {
442
456
  id: "screenshot";
443
- url: string;
457
+ url?: string;
458
+ load?: () => Promise<string | null>;
444
459
  } | {
445
460
  id: "metadata";
446
461
  entries: readonly MetadataEntry[];
@@ -639,8 +654,9 @@ interface View {
639
654
  * when the declared target has been removed from the host.
640
655
  */
641
656
  focusTarget?: (root: HTMLElement, ctx: ViewContext) => HTMLElement | null;
642
- surface: (ctx: ViewContext) => ViewSurface;
643
- /** Direct render for integration adapters (React, etc.). Mutually exclusive with surface renderers. */
657
+ /** Required unless `render` is provided. */
658
+ surface?: (ctx: ViewContext) => ViewSurface;
659
+ /** Direct render for integration adapters (React, etc.). Takes precedence over `surface` when both are present. */
644
660
  render?: (ctx: ViewContext, root: HTMLElement) => Cleanup | void;
645
661
  parent?: (ref: EntityRef | null) => ViewStackEntry | null;
646
662
  }
@@ -94,6 +94,7 @@ interface ReportRecord {
94
94
  interface Registry {
95
95
  add(entity: Entity): void;
96
96
  get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
97
+ matchPattern<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
97
98
  list<K extends EntityKind>(kind: K): ReadonlyArray<EntityByKind<K>>;
98
99
  query(predicate: (entity: Entity) => boolean): Entity[];
99
100
  byScope(scope: Scope): Entity[];
@@ -101,88 +102,10 @@ interface Registry {
101
102
  setReports(kind: EntityKind, id: string, reports: readonly ReportRecord[]): void;
102
103
  getReports(kind: EntityKind, id: string): readonly ReportRecord[];
103
104
  listReportKeys(): readonly string[];
104
- archiveReport?: (reportId: string, reason?: string) => void | Promise<void>;
105
+ closeReport?: (reportId: string, status?: string) => void | Promise<void>;
105
106
  onReportsChange(cb: () => void): () => void;
106
107
  }
107
108
 
108
- interface UserIdentity {
109
- id: string;
110
- name?: string;
111
- avatar?: string;
112
- }
113
-
114
- type ThemePreference = "light" | "dark" | "auto";
115
- type ResolvedTheme = "light" | "dark";
116
- interface ViewStackEntry {
117
- id: string;
118
- ref: EntityRef | null;
119
- }
120
- interface SessionSnapshot {
121
- hover: EntityRef | null;
122
- selection: EntityRef | null;
123
- stack: ViewStackEntry[];
124
- /** Sticky overlay highlight. Set by "Highlight Element" actions; cleared on Esc. */
125
- pinnedHighlight: EntityRef | null;
126
- inspectorActive: boolean;
127
- theme: ThemePreference;
128
- resolvedTheme: ResolvedTheme;
129
- ingestActive: boolean;
130
- /**
131
- * Identity for the local user. Set once at session creation; gates realtime
132
- * features (cursor labels, presence) and auto-populates report attribution.
133
- */
134
- user: UserIdentity | null;
135
- }
136
- type SessionState = SessionSnapshot;
137
-
138
- interface NavigationState {
139
- stack: ViewStackEntry[];
140
- }
141
- interface NavigationActions {
142
- push(entry: ViewStackEntry): void;
143
- pop(): void;
144
- replace(entry: ViewStackEntry): void;
145
- clear(): void;
146
- reset(stack: ViewStackEntry[]): void;
147
- }
148
- type NavigationStore = StoreApi<NavigationState> & {
149
- nav: NavigationActions;
150
- };
151
-
152
- type SurfaceMode = "idle" | "inspecting" | "palette" | "viewing";
153
- interface ModeSnapshot {
154
- mode: SurfaceMode;
155
- inspectorActive: boolean;
156
- }
157
- interface ModeTransitions {
158
- openPalette(): void;
159
- openInspector(): void;
160
- closeInspector(): void;
161
- toggleInspector(): void;
162
- enterViewing(initialStack: ViewStackEntry[]): void;
163
- dismiss(): void;
164
- popOrTransition(): void;
165
- pushView(entry: ViewStackEntry): void;
166
- }
167
- type ModeStore = StoreApi<ModeSnapshot> & {
168
- transition: ModeTransitions;
169
- };
170
-
171
- interface HighlightActions {
172
- hover(ref: EntityRef, element?: HTMLElement | null, color?: string | null): void;
173
- unhover(): void;
174
- pin(ref?: EntityRef): void;
175
- unpin(): void;
176
- }
177
- type SessionStore = StoreApi<SessionState> & {
178
- readonly nav: NavigationStore;
179
- readonly mode: ModeStore;
180
- readonly highlight: HighlightActions;
181
- select(ref: EntityRef | null): void;
182
- setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
183
- setIngest(active: boolean): void;
184
- };
185
-
186
109
  type ConsoleLevel = "warn" | "error";
187
110
  interface ConsoleEntry {
188
111
  level: ConsoleLevel;
@@ -224,6 +147,12 @@ interface NetworkCapture {
224
147
  clear(): void;
225
148
  }
226
149
 
150
+ interface UserIdentity {
151
+ id: string;
152
+ name?: string;
153
+ avatar?: string;
154
+ }
155
+
227
156
  type RealtimePresenceUser = {
228
157
  userId: string;
229
158
  name: string;
@@ -241,6 +170,8 @@ interface RealtimeChannel {
241
170
  joinRoute(route: string): void;
242
171
  onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
243
172
  onPin(cb: (pin: PinRecord) => void): () => void;
173
+ /** Optional so pre-existing channel stubs keep satisfying the interface. */
174
+ onPinArchived?(cb: (reportId: string) => void): () => void;
244
175
  }
245
176
  interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
246
177
  getConfig(): Promise<IngestConfig>;
@@ -262,8 +193,17 @@ interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegr
262
193
  route?: string;
263
194
  entities?: string;
264
195
  }): Promise<PinRecord[]>;
265
- archive(reportId: string, reason?: ArchiveReason): Promise<void>;
196
+ /**
197
+ * Pin records travel without their screenshot (kept out of `pins.list`
198
+ * so multi-MB frames don't stall the shared socket); the report detail
199
+ * view fetches it lazily through here. Optional for host-provided
200
+ * adapters that inline screenshots on the record instead.
201
+ */
202
+ screenshot?(reportId: string): Promise<string | null>;
203
+ close(reportId: string, reason?: ArchiveReason): Promise<void>;
266
204
  };
205
+ /** Closes the adapter's shared socket. Any later RPC call revives it. */
206
+ dispose?(): void;
267
207
  }
268
208
 
269
209
  interface IngestOptions {
@@ -283,6 +223,74 @@ interface Ingest {
283
223
  readonly network: NetworkCapture | null;
284
224
  }
285
225
 
226
+ type ThemePreference = "light" | "dark" | "auto";
227
+ type ResolvedTheme = "light" | "dark";
228
+ interface ViewStackEntry {
229
+ id: string;
230
+ ref: EntityRef | null;
231
+ }
232
+ interface SessionSnapshot {
233
+ stack: ViewStackEntry[];
234
+ /** Sticky overlay highlight. Set by "Highlight Element" actions; cleared on Esc. */
235
+ pinnedHighlight: EntityRef | null;
236
+ /** Mirrored from the mode store; the surface mode the session is currently in. */
237
+ mode: SurfaceMode;
238
+ theme: ThemePreference;
239
+ resolvedTheme: ResolvedTheme;
240
+ /**
241
+ * Identity for the local user. Set once at session creation; gates realtime
242
+ * features (cursor labels, presence) and auto-populates report attribution.
243
+ */
244
+ user: UserIdentity | null;
245
+ }
246
+ type SessionState = SessionSnapshot;
247
+
248
+ interface NavigationState {
249
+ stack: ViewStackEntry[];
250
+ }
251
+ interface NavigationActions {
252
+ push(entry: ViewStackEntry): void;
253
+ pop(): void;
254
+ clear(): void;
255
+ reset(stack: ViewStackEntry[]): void;
256
+ }
257
+ type NavigationStore = StoreApi<NavigationState> & {
258
+ nav: NavigationActions;
259
+ };
260
+
261
+ type SurfaceMode = "idle" | "inspecting" | "palette" | "viewing";
262
+ interface ModeSnapshot {
263
+ mode: SurfaceMode;
264
+ }
265
+ interface ModeTransitions {
266
+ openPalette(): void;
267
+ openInspector(): void;
268
+ closeInspector(): void;
269
+ toggleInspector(): void;
270
+ enterViewing(initialStack: ViewStackEntry[]): void;
271
+ dismiss(): void;
272
+ popOrTransition(): void;
273
+ pushView(entry: ViewStackEntry): void;
274
+ }
275
+ type ModeStore = StoreApi<ModeSnapshot> & {
276
+ transition: ModeTransitions;
277
+ };
278
+
279
+ interface HighlightActions {
280
+ hover(ref: EntityRef, element?: HTMLElement | null, color?: string | null): void;
281
+ unhover(): void;
282
+ pin(ref?: EntityRef): void;
283
+ unpin(): void;
284
+ }
285
+ type SessionStore = StoreApi<SessionState> & {
286
+ readonly nav: NavigationStore;
287
+ readonly mode: ModeStore;
288
+ readonly highlight: HighlightActions;
289
+ setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
290
+ };
291
+
292
+ type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
293
+
286
294
  interface OverlayShowOptions {
287
295
  label?: string;
288
296
  color?: string;
@@ -293,8 +301,6 @@ interface OverlayShowOptions {
293
301
  backdrop?: boolean;
294
302
  }
295
303
 
296
- type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
297
-
298
304
  interface RouteMatch {
299
305
  view: View;
300
306
  priority: number;
@@ -362,6 +368,8 @@ interface DetailSurface {
362
368
  entityKind: EntityKind;
363
369
  /** Registry lookup failed — renders the "not found" placeholder. */
364
370
  notFound?: EntityRef;
371
+ /** Entity exists in the DOM but not in the registry (gen file). */
372
+ unregistered?: boolean;
365
373
  /** Entity display name, rendered as the heading. */
366
374
  title?: string;
367
375
  subtitle?: DetailSubtitle;
@@ -438,9 +446,16 @@ type DetailSection = {
438
446
  id: "routes";
439
447
  paths: readonly string[];
440
448
  filterable?: boolean;
441
- } | {
449
+ }
450
+ /**
451
+ * `url` renders immediately; `load` fetches lazily (cloud pins travel
452
+ * without their screenshot) and the section stays hidden until — and
453
+ * unless — the promise resolves with a data URL.
454
+ */
455
+ | {
442
456
  id: "screenshot";
443
- url: string;
457
+ url?: string;
458
+ load?: () => Promise<string | null>;
444
459
  } | {
445
460
  id: "metadata";
446
461
  entries: readonly MetadataEntry[];
@@ -639,8 +654,9 @@ interface View {
639
654
  * when the declared target has been removed from the host.
640
655
  */
641
656
  focusTarget?: (root: HTMLElement, ctx: ViewContext) => HTMLElement | null;
642
- surface: (ctx: ViewContext) => ViewSurface;
643
- /** Direct render for integration adapters (React, etc.). Mutually exclusive with surface renderers. */
657
+ /** Required unless `render` is provided. */
658
+ surface?: (ctx: ViewContext) => ViewSurface;
659
+ /** Direct render for integration adapters (React, etc.). Takes precedence over `surface` when both are present. */
644
660
  render?: (ctx: ViewContext, root: HTMLElement) => Cleanup | void;
645
661
  parent?: (ref: EntityRef | null) => ViewStackEntry | null;
646
662
  }