cozyclay 3.2.0 → 3.2.1

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 (185) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/INSTALL_FOR_AGENTS.md +4 -4
  3. package/README.md +4 -2
  4. package/bin/agent/agent-failure-codes.mjs +34 -8
  5. package/bin/agent/agent-routes.mjs +6 -6
  6. package/bin/agent/agent-runner.mjs +16 -13
  7. package/bin/agent/agent-stream.mjs +26 -3
  8. package/bin/agent/main-prompt.mjs +1 -1
  9. package/bin/agent/studio-prompt.mjs +2 -2
  10. package/bin/agent/supervisor-followup.mjs +34 -0
  11. package/bin/agent/supervisor.mjs +6 -6
  12. package/bin/cozyclay.mjs +23 -60
  13. package/bin/star-prompt.mjs +15 -14
  14. package/bin/studio-routes.mjs +6 -3
  15. package/bin/telemetry-state.mjs +5 -7
  16. package/bin/update-check.mjs +61 -7
  17. package/bin/update-install.mjs +16 -3
  18. package/bin/update-restart.mjs +95 -0
  19. package/bin/update-routes.mjs +25 -3
  20. package/dist/app/index.html +13 -7
  21. package/dist/assets/TaskBoard-tgO0MNKL.js +1 -0
  22. package/dist/assets/analytics-CaTUuLPM.js +1 -0
  23. package/dist/assets/app-CnDkB5WO.css +1 -0
  24. package/dist/assets/app-DJt06Oyb.js +5144 -0
  25. package/dist/assets/{compile-worker-DRWRa9pr.js → compile-worker-D1pl6G7x.js} +5 -5
  26. package/dist/assets/landing-2Fy7DU41.js +1 -0
  27. package/dist/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
  28. package/dist/assets/motion3-compile-BxaM0Xwl.js +1 -0
  29. package/dist/assets/scene-asset-sync-CLGNbEBq.js +13 -0
  30. package/dist/assets/task-board-UVGTZLRF.js +15 -0
  31. package/dist/assets/workflow-CSiBlX1s.js +179 -0
  32. package/dist/cozyclay-package.json +1 -1
  33. package/dist/index.html +4 -1
  34. package/dist/privacy/index.html +9 -6
  35. package/dist/sitemap.xml +2 -2
  36. package/dist/workflow/index.html +5 -4
  37. package/mcp/README.md +1 -1
  38. package/mcp/live-hub.mjs +4 -4
  39. package/mcp/tool-handlers.mjs +14 -16
  40. package/package.json +2 -1
  41. package/src/App.jsx +37 -70
  42. package/src/analytics-controls.js +25 -3
  43. package/src/analytics-strict.js +16 -4
  44. package/src/analytics.js +32 -26
  45. package/src/app-version.js +13 -0
  46. package/src/asset-drop.js +39 -0
  47. package/src/asset-pane.css +34 -0
  48. package/src/asset-pane.jsx +4 -35
  49. package/src/bus-tasks.js +1 -1
  50. package/src/character-kind.js +8 -6
  51. package/src/click-friction.js +5 -4
  52. package/src/command-bus-telemetry.js +8 -7
  53. package/src/command-bus.js +2 -16
  54. package/src/commands/cast.js +2 -1
  55. package/src/commands/motion3.js +3 -1
  56. package/src/commands/objects.js +2 -37
  57. package/src/commands/project.js +3 -3
  58. package/src/commands/sculpt-compare.js +53 -0
  59. package/src/content-tile.jsx +36 -0
  60. package/src/domains/cast.js +7 -6
  61. package/src/domains/motion.js +6 -5
  62. package/src/domains/scenes.js +41 -31
  63. package/src/execution-telemetry.js +7 -3
  64. package/src/export-menu-telemetry.js +26 -0
  65. package/src/finger-handles.jsx +128 -0
  66. package/src/friction-hint.js +82 -0
  67. package/src/live-control.js +2 -1
  68. package/src/locale-zh/panels.js +20 -0
  69. package/src/locale-zh/shell.js +4 -0
  70. package/src/locale-zh/workspace.js +6 -0
  71. package/src/motion/find-bone.js +13 -0
  72. package/src/motion/fingers.js +170 -0
  73. package/src/motion/fingertip-pick.js +21 -0
  74. package/src/motion/ik-exposure.js +48 -0
  75. package/src/motion/ik.js +4 -11
  76. package/src/motion3/compiler/head-lead.js +4 -2
  77. package/src/motion3/hybrid-hint.js +19 -0
  78. package/src/motion3/load.js +19 -12
  79. package/src/motion3/qa/hints-contact.js +12 -0
  80. package/src/motion3/qa/patch.js +4 -1
  81. package/src/motion3/qa/verdict.js +7 -2
  82. package/src/motion3/repair.js +28 -8
  83. package/src/motion3/skills/catch.js +2 -1
  84. package/src/panels/FingerPanel.jsx +38 -0
  85. package/src/panels/RigControlPanel.jsx +9 -1
  86. package/src/panels/SculptPanel.jsx +12 -12
  87. package/src/panels/SculptPartTree.jsx +46 -0
  88. package/src/panels/SubjectsPanel.jsx +1 -1
  89. package/src/panels/sculpt.css +11 -0
  90. package/src/pose-fade.js +7 -3
  91. package/src/posestudio.jsx +14 -27
  92. package/src/project-browser.css +6 -0
  93. package/src/project-browser.jsx +9 -18
  94. package/src/project-start-choices.jsx +45 -0
  95. package/src/project.js +16 -12
  96. package/src/proxy-figure-shape.js +11 -0
  97. package/src/proxy-figure.jsx +25 -18
  98. package/src/scene-assets.js +17 -13
  99. package/src/scenes.js +22 -11
  100. package/src/sculpt-blueprint.js +56 -0
  101. package/src/sculpt-mode.js +5 -0
  102. package/src/sculpt-part-edit.js +115 -0
  103. package/src/sculpt-part-gizmo.jsx +159 -0
  104. package/src/sculpt-part-outline.jsx +72 -0
  105. package/src/sculpt-pick.js +53 -0
  106. package/src/sculpt-run-text.js +51 -0
  107. package/src/sculpt-run.js +10 -46
  108. package/src/sculpt-shelf-file.js +92 -0
  109. package/src/sculpt-shelf-tiles.jsx +69 -0
  110. package/src/sculpt-shelf.js +108 -0
  111. package/src/sculpt-stage.jsx +39 -2
  112. package/src/sculpt-thumb.js +72 -0
  113. package/src/sculpt-views.js +75 -0
  114. package/src/semantic-edit.js +0 -87
  115. package/src/settings-menu.jsx +2 -2
  116. package/src/shell/DetailsSlot.jsx +5 -6
  117. package/src/shell/LibrarySlot.jsx +8 -10
  118. package/src/shell/MenuBar.jsx +6 -6
  119. package/src/shell/PreferencesDialog.jsx +2 -3
  120. package/src/shell/ViewportToolbar.jsx +15 -18
  121. package/src/shell/add-character-entries.js +13 -0
  122. package/src/shell/pose-controls.js +32 -0
  123. package/src/shell/preference-pages.jsx +2 -11
  124. package/src/shell/storyboard-caption.js +21 -0
  125. package/src/shell/studio-shell-context.js +1 -0
  126. package/src/shortcut-friction.js +2 -1
  127. package/src/site/landing-analytics.js +28 -0
  128. package/src/studio-actions.js +3 -2
  129. package/src/studio-agent-protocol.js +4 -4
  130. package/src/studio-app-binding.js +4 -3
  131. package/src/update/UpdateChip.jsx +21 -2
  132. package/src/update/UpdateDialog.jsx +26 -6
  133. package/src/update/update-client.js +123 -17
  134. package/src/update/update-telemetry.js +15 -3
  135. package/src/use-sculpt-mode.js +62 -8
  136. package/src/workflow/agent-failure-codes.js +28 -9
  137. package/src/workflow/agent-turn-telemetry.js +1 -1
  138. package/src/workflow/task-board.js +2 -2
  139. package/tools/dev/page-shell.py +1 -1
  140. package/tools/dev/pages/greybox-to-video.html +21 -2
  141. package/tools/dev/pages/previs-software.html +3 -3
  142. package/tools/dev/pages/privacy.html +9 -6
  143. package/tools/dev/pages/seedance-camera-control.html +2 -2
  144. package/tools/loc-baseline.json +10 -10
  145. package/tools/run-tests.mjs +45 -69
  146. package/tools/select-tests.mjs +119 -0
  147. package/tools/test-durations.json +455 -0
  148. package/tools/test-graph.mjs +181 -0
  149. package/tools/test-shards.mjs +78 -0
  150. package/tools/tutorial/README.md +74 -0
  151. package/tools/tutorial/assemble.mjs +43 -0
  152. package/tools/tutorial/captions.mjs +43 -0
  153. package/tools/tutorial/cdp.mjs +55 -0
  154. package/tools/tutorial/cursor.mjs +159 -0
  155. package/tools/tutorial/episode.mjs +173 -0
  156. package/tools/tutorial/episodes/beginner-guide/00-install.mjs +42 -0
  157. package/tools/tutorial/episodes/beginner-guide/01-start.mjs +50 -0
  158. package/tools/tutorial/episodes/beginner-guide/02-layout.mjs +67 -0
  159. package/tools/tutorial/episodes/beginner-guide/03-stage.mjs +58 -0
  160. package/tools/tutorial/episodes/beginner-guide/04-motion.mjs +98 -0
  161. package/tools/tutorial/episodes/beginner-guide/05-camera.mjs +47 -0
  162. package/tools/tutorial/episodes/beginner-guide/06-export.mjs +59 -0
  163. package/tools/tutorial/episodes/beginner-guide/steps.mjs +32 -0
  164. package/tools/tutorial/episodes/beginner-guide.mjs +17 -0
  165. package/tools/tutorial/episodes/cast.mjs +12 -0
  166. package/tools/tutorial/episodes/first-video.mjs +121 -0
  167. package/tools/tutorial/episodes/stub-tour.mjs +97 -0
  168. package/tools/tutorial/launch.mjs +63 -0
  169. package/tools/tutorial/mux.mjs +61 -0
  170. package/tools/tutorial/overlay.mjs +142 -0
  171. package/tools/tutorial/record.mjs +156 -0
  172. package/tools/tutorial/scenes/terminal.html +63 -0
  173. package/tools/tutorial/steps.mjs +111 -0
  174. package/tools/tutorial/terminal.mjs +43 -0
  175. package/tools/tutorial/voice.mjs +49 -0
  176. package/tools/update-test-durations.mjs +42 -0
  177. package/tools/verify-package-tarball.mjs +18 -12
  178. package/dist/assets/TaskBoard-BUjjuvm5.js +0 -1
  179. package/dist/assets/app-Dige7q3X.css +0 -1
  180. package/dist/assets/app-DxoI941o.js +0 -5144
  181. package/dist/assets/motion3-compile-B4SX4TGx.js +0 -1
  182. package/dist/assets/rolldown-runtime-hePW80VL.js +0 -1
  183. package/dist/assets/scene-asset-sync-LeI3eSnO.js +0 -13
  184. package/dist/assets/task-board-5PKn7ZaA.js +0 -15
  185. package/dist/assets/workflow-Dg9jCKOq.js +0 -179
@@ -0,0 +1,455 @@
1
+ {
2
+ "mcp/verify-http-origin.mjs": 0.4,
3
+ "mcp/verify-import-mesh.mjs": 0.1,
4
+ "mcp/verify-live-controller.mjs": 0.5,
5
+ "mcp/verify-live-execution.mjs": 0.1,
6
+ "mcp/verify-live-p0.mjs": 0.3,
7
+ "mcp/verify-live-port.mjs": 1.8,
8
+ "mcp/verify-live-proxy-frame.mjs": 3.3,
9
+ "mcp/verify-live-routing.mjs": 0.3,
10
+ "mcp/verify-live.mjs": 5.2,
11
+ "mcp/verify-project-camera.mjs": 0.2,
12
+ "mcp/verify-protocol-version.mjs": 0.4,
13
+ "mcp/verify-sculpt-object.mjs": 0.2,
14
+ "mcp/verify-tool-annotations.mjs": 0.2,
15
+ "mcp/verify.mjs": 0.3,
16
+ "test/ardy/verify-collision-blockers.mjs": 0.1,
17
+ "test/ardy/verify-key-runs.mjs": 0,
18
+ "test/ardy/verify-playback-clock.mjs": 0,
19
+ "test/ardy/verify-timeline-coordinates.mjs": 0,
20
+ "test/bus/verify-adapters.mjs": 1.5,
21
+ "test/bus/verify-agent-path-readers.mjs": 0,
22
+ "test/bus/verify-agent-path-retirement.mjs": 0.2,
23
+ "test/bus/verify-agent-progress-card.mjs": 0.1,
24
+ "test/bus/verify-agent-progress.mjs": 2.7,
25
+ "test/bus/verify-agent-receipts.mjs": 12.1,
26
+ "test/bus/verify-agent-suite-compatibility.mjs": 0.4,
27
+ "test/bus/verify-app-context.mjs": 1.7,
28
+ "test/bus/verify-app-domain-writers.mjs": 0.1,
29
+ "test/bus/verify-app-session-composition.mjs": 2.9,
30
+ "test/bus/verify-app-turn-undo.mjs": 2.2,
31
+ "test/bus/verify-atomic-native.mjs": 1.4,
32
+ "test/bus/verify-beat-board.mjs": 2.2,
33
+ "test/bus/verify-bench-motion.mjs": 0.1,
34
+ "test/bus/verify-browser-navigation.mjs": 0.1,
35
+ "test/bus/verify-bus-coverage.mjs": 0.3,
36
+ "test/bus/verify-bus-friction-events.mjs": 1.4,
37
+ "test/bus/verify-bus-tasks.mjs": 4.3,
38
+ "test/bus/verify-cast-commands.mjs": 18.3,
39
+ "test/bus/verify-cast-gesture-pose-boundaries.mjs": 2.1,
40
+ "test/bus/verify-cast-metrics.mjs": 0.4,
41
+ "test/bus/verify-cast-proxy-figure.mjs": 3.3,
42
+ "test/bus/verify-cast-ui-routing.mjs": 2,
43
+ "test/bus/verify-collection-boundaries.mjs": 2,
44
+ "test/bus/verify-collection-kind.mjs": 1.8,
45
+ "test/bus/verify-collection-refusals.mjs": 1.8,
46
+ "test/bus/verify-command-declarations.mjs": 0.1,
47
+ "test/bus/verify-command-registry.mjs": 0.2,
48
+ "test/bus/verify-cross-domain-history.mjs": 2.9,
49
+ "test/bus/verify-discovery.mjs": 3.4,
50
+ "test/bus/verify-document-read-budget.mjs": 0.3,
51
+ "test/bus/verify-document-store-cancel.mjs": 0.1,
52
+ "test/bus/verify-document-store-guard.mjs": 0.1,
53
+ "test/bus/verify-document-store-interleave.mjs": 0.1,
54
+ "test/bus/verify-document-store-legacy.mjs": 0,
55
+ "test/bus/verify-document-store-native-retention.mjs": 0,
56
+ "test/bus/verify-document-store-react.mjs": 0.2,
57
+ "test/bus/verify-document-store-retention.mjs": 0.1,
58
+ "test/bus/verify-document-store-runtime.mjs": 0.1,
59
+ "test/bus/verify-document-store.mjs": 0.1,
60
+ "test/bus/verify-domain-modules.mjs": 0.6,
61
+ "test/bus/verify-draft-ghost.mjs": 0,
62
+ "test/bus/verify-effects.mjs": 0.1,
63
+ "test/bus/verify-element-document-key.mjs": 1.8,
64
+ "test/bus/verify-element-kinds.mjs": 0.1,
65
+ "test/bus/verify-element-lifecycle-readback.mjs": 1.8,
66
+ "test/bus/verify-element-null-base.mjs": 1.8,
67
+ "test/bus/verify-element-split-fields.mjs": 1.8,
68
+ "test/bus/verify-export-framing.mjs": 0.2,
69
+ "test/bus/verify-exposure.mjs": 0.1,
70
+ "test/bus/verify-final-suite-compatibility.mjs": 3.7,
71
+ "test/bus/verify-fixture-root.mjs": 3.4,
72
+ "test/bus/verify-friction-counters.mjs": 1.5,
73
+ "test/bus/verify-held-object-pose.mjs": 0.1,
74
+ "test/bus/verify-history-app.mjs": 3.1,
75
+ "test/bus/verify-history-receipt-parity.mjs": 0.1,
76
+ "test/bus/verify-inspect-bounds.mjs": 2.8,
77
+ "test/bus/verify-inspection-alias-filters.mjs": 1.5,
78
+ "test/bus/verify-job-control-revision.mjs": 0.1,
79
+ "test/bus/verify-job-detach.mjs": 0.1,
80
+ "test/bus/verify-job-self-edit.mjs": 0.1,
81
+ "test/bus/verify-jobs.mjs": 0.1,
82
+ "test/bus/verify-kit-take-only-parts.mjs": 0.1,
83
+ "test/bus/verify-kits.mjs": 2.7,
84
+ "test/bus/verify-light-blocked.mjs": 2.5,
85
+ "test/bus/verify-load-scenes-exposure.mjs": 0.1,
86
+ "test/bus/verify-manifest.mjs": 0.3,
87
+ "test/bus/verify-module-declarations.mjs": 0.1,
88
+ "test/bus/verify-motion-agent-loc.mjs": 0.1,
89
+ "test/bus/verify-motion-commands.mjs": 31.1,
90
+ "test/bus/verify-motion-install-ifclean.mjs": 2.7,
91
+ "test/bus/verify-motion-keyobject.mjs": 5.7,
92
+ "test/bus/verify-motion-multichar.mjs": 6,
93
+ "test/bus/verify-motion-private-owners-removed.mjs": 0.1,
94
+ "test/bus/verify-motion-retired-protocol.mjs": 0.1,
95
+ "test/bus/verify-motion-ui-physics.mjs": 4.1,
96
+ "test/bus/verify-motion3-aim.mjs": 2.8,
97
+ "test/bus/verify-motion3-armorient.mjs": 3.4,
98
+ "test/bus/verify-motion3-bat-robust.mjs": 16.2,
99
+ "test/bus/verify-motion3-carried-anchor.mjs": 0.3,
100
+ "test/bus/verify-motion3-compile-worker.mjs": 7.8,
101
+ "test/bus/verify-motion3-corrections.mjs": 2.1,
102
+ "test/bus/verify-motion3-elbow.mjs": 13.7,
103
+ "test/bus/verify-motion3-examples.mjs": 5.4,
104
+ "test/bus/verify-motion3-follow.mjs": 1.6,
105
+ "test/bus/verify-motion3-foot-collide.mjs": 1.6,
106
+ "test/bus/verify-motion3-free-objects.mjs": 7.1,
107
+ "test/bus/verify-motion3-gait.mjs": 1.2,
108
+ "test/bus/verify-motion3-goal-predicates.mjs": 0.4,
109
+ "test/bus/verify-motion3-grab-grip.mjs": 2,
110
+ "test/bus/verify-motion3-grip.mjs": 0.7,
111
+ "test/bus/verify-motion3-ground.mjs": 13.3,
112
+ "test/bus/verify-motion3-input-fixes.mjs": 1,
113
+ "test/bus/verify-motion3-keyed-second-anchor.mjs": 0.3,
114
+ "test/bus/verify-motion3-knee.mjs": 3.8,
115
+ "test/bus/verify-motion3-lean.mjs": 10.8,
116
+ "test/bus/verify-motion3-lenient.mjs": 21.6,
117
+ "test/bus/verify-motion3-near.mjs": 0.1,
118
+ "test/bus/verify-motion3-path-grip.mjs": 9.2,
119
+ "test/bus/verify-motion3-qa-spikes.mjs": 5.9,
120
+ "test/bus/verify-motion3-stance.mjs": 1.6,
121
+ "test/bus/verify-motion3-switch.mjs": 0.2,
122
+ "test/bus/verify-motion3-wrist-clamp.mjs": 0,
123
+ "test/bus/verify-motion3-wrist-qa.mjs": 1.3,
124
+ "test/bus/verify-native-roundtrip.mjs": 5.9,
125
+ "test/bus/verify-object-look.mjs": 0.1,
126
+ "test/bus/verify-objects-boundaries.mjs": 2.5,
127
+ "test/bus/verify-objects-commands.mjs": 6.7,
128
+ "test/bus/verify-objects-gesture-undo.mjs": 2.3,
129
+ "test/bus/verify-objects-gestures.mjs": 2.4,
130
+ "test/bus/verify-objects-group-carry.mjs": 3.6,
131
+ "test/bus/verify-objects-group-rotation.mjs": 2.3,
132
+ "test/bus/verify-objects-import.mjs": 2.3,
133
+ "test/bus/verify-objects-metrics.mjs": 7.3,
134
+ "test/bus/verify-objects-panel.mjs": 2.3,
135
+ "test/bus/verify-objects-parity.mjs": 17.1,
136
+ "test/bus/verify-objects-strict-initializer.mjs": 2.3,
137
+ "test/bus/verify-objects-surfaces.mjs": 2.7,
138
+ "test/bus/verify-one-history-removal.mjs": 0.1,
139
+ "test/bus/verify-one-history.mjs": 0.1,
140
+ "test/bus/verify-owned-session-composition.mjs": 3.5,
141
+ "test/bus/verify-parity-matrix.mjs": 7.1,
142
+ "test/bus/verify-parity-pending.mjs": 7.1,
143
+ "test/bus/verify-project-adapters.mjs": 2.7,
144
+ "test/bus/verify-project-boundaries.mjs": 5.2,
145
+ "test/bus/verify-project-checkpoints.mjs": 2.9,
146
+ "test/bus/verify-project-commands.mjs": 2.7,
147
+ "test/bus/verify-project-files.mjs": 2.6,
148
+ "test/bus/verify-project-panel.mjs": 2.7,
149
+ "test/bus/verify-project-parity.mjs": 7.6,
150
+ "test/bus/verify-project-projections.mjs": 2.9,
151
+ "test/bus/verify-range-pin-domain.mjs": 2.4,
152
+ "test/bus/verify-readonly-actions.mjs": 0.1,
153
+ "test/bus/verify-receipts.mjs": 0.1,
154
+ "test/bus/verify-refusals.mjs": 0.1,
155
+ "test/bus/verify-shot-frame-export-camera.mjs": 2,
156
+ "test/bus/verify-shot-range-aliases.mjs": 2.9,
157
+ "test/bus/verify-shots-app-line.mjs": 0.1,
158
+ "test/bus/verify-shots-commands.mjs": 20,
159
+ "test/bus/verify-shots-extent-undo.mjs": 1.4,
160
+ "test/bus/verify-shots-preset-history.mjs": 2.4,
161
+ "test/bus/verify-shots-surfaces.mjs": 1.9,
162
+ "test/bus/verify-smoke-kit-take-only.mjs": 1.7,
163
+ "test/bus/verify-smoke-pacing.mjs": 5.2,
164
+ "test/bus/verify-stage-cast-history.mjs": 1.8,
165
+ "test/bus/verify-stage-document-read.mjs": 1.9,
166
+ "test/bus/verify-stage-domain.mjs": 6.6,
167
+ "test/bus/verify-stage-empty-readback.mjs": 2,
168
+ "test/bus/verify-stage-envao.mjs": 2.1,
169
+ "test/bus/verify-stage-gestures.mjs": 1.8,
170
+ "test/bus/verify-stage-hdr.mjs": 2.3,
171
+ "test/bus/verify-stage-history-order.mjs": 2,
172
+ "test/bus/verify-stage-lighting.mjs": 1.9,
173
+ "test/bus/verify-stage-load.mjs": 1.9,
174
+ "test/bus/verify-stage-metrics.mjs": 7.3,
175
+ "test/bus/verify-stage-patch-alias.mjs": 11.7,
176
+ "test/bus/verify-stage-set.mjs": 1.8,
177
+ "test/bus/verify-stage-write-guard.mjs": 1.9,
178
+ "test/bus/verify-stale-fence-messages.mjs": 0.1,
179
+ "test/bus/verify-store-domain-binding.mjs": 1.8,
180
+ "test/bus/verify-store-domain-load.mjs": 1.9,
181
+ "test/bus/verify-store-domain-routing.mjs": 1.5,
182
+ "test/bus/verify-take-v3-grab-persist.mjs": 3,
183
+ "test/bus/verify-take-v3-persist.mjs": 3.8,
184
+ "test/bus/verify-timeouts.mjs": 0.1,
185
+ "test/bus/verify-toast-language.mjs": 0,
186
+ "test/bus/verify-tool-alias.mjs": 1.8,
187
+ "test/bus/verify-transaction-refusals.mjs": 0.1,
188
+ "test/bus/verify-transactions.mjs": 0.1,
189
+ "test/bus/verify-transient-writer-boundaries.mjs": 2.8,
190
+ "test/bus/verify-undo-expiry.mjs": 0.1,
191
+ "test/bus/verify-user-edit-buckets.mjs": 2.1,
192
+ "test/bus/verify-view-alias-receipts.mjs": 1.7,
193
+ "test/bus/verify-view-ghosts.mjs": 1.5,
194
+ "test/bus/verify-view-mode-pose.mjs": 1.9,
195
+ "test/demo/verify-api-routes.mjs": 0,
196
+ "test/ik/translation-step.mjs": 0,
197
+ "test/ik/verify-collision-capsules.mjs": 0.1,
198
+ "test/ik/verify-contact-project.mjs": 0.1,
199
+ "test/ik/verify-ground.mjs": 0.1,
200
+ "test/ik/verify-ik-blend-range.mjs": 0.1,
201
+ "test/ik/verify-ik-drag-delta.mjs": 0.1,
202
+ "test/ik/verify-ik-pick.mjs": 0,
203
+ "test/ik/verify-ik.mjs": 0.1,
204
+ "test/ik/verify-knee-side.mjs": 0.1,
205
+ "test/ik/verify-physics-review.mjs": 0,
206
+ "test/ik/verify-physics-support.mjs": 0.1,
207
+ "test/ik/verify-physics-surface.mjs": 1.6,
208
+ "test/ik/verify-range-pin-object-transform.mjs": 0,
209
+ "test/ik/verify-range-pin-ui.mjs": 0,
210
+ "test/ik/verify-range-pin.mjs": 0.1,
211
+ "test/motion3/verify-motion3-agentloop.mjs": 11.1,
212
+ "test/motion3/verify-motion3-arm.mjs": 4.1,
213
+ "test/motion3/verify-motion3-balance.mjs": 0.2,
214
+ "test/motion3/verify-motion3-carried.mjs": 7.8,
215
+ "test/motion3/verify-motion3-catch.mjs": 0.7,
216
+ "test/motion3/verify-motion3-commands.mjs": 1,
217
+ "test/motion3/verify-motion3-contracts.mjs": 1.6,
218
+ "test/motion3/verify-motion3-core.mjs": 0.3,
219
+ "test/motion3/verify-motion3-cup.mjs": 2.2,
220
+ "test/motion3/verify-motion3-describe.mjs": 2,
221
+ "test/motion3/verify-motion3-exitcar.mjs": 1.4,
222
+ "test/motion3/verify-motion3-finger-contact.mjs": 1,
223
+ "test/motion3/verify-motion3-finger-pose.mjs": 2.4,
224
+ "test/motion3/verify-motion3-flip.mjs": 0.4,
225
+ "test/motion3/verify-motion3-float-fix.mjs": 0.4,
226
+ "test/motion3/verify-motion3-gait.mjs": 0.8,
227
+ "test/motion3/verify-motion3-goals.mjs": 0.9,
228
+ "test/motion3/verify-motion3-grab-blend.mjs": 2.8,
229
+ "test/motion3/verify-motion3-grab.mjs": 1.6,
230
+ "test/motion3/verify-motion3-grasp-fields.mjs": 1.3,
231
+ "test/motion3/verify-motion3-grasp-friction.mjs": 1.3,
232
+ "test/motion3/verify-motion3-grasp-hints.mjs": 0.9,
233
+ "test/motion3/verify-motion3-grasp-measure.mjs": 0.7,
234
+ "test/motion3/verify-motion3-grasp-qa.mjs": 2,
235
+ "test/motion3/verify-motion3-headlead.mjs": 1.1,
236
+ "test/motion3/verify-motion3-hit.mjs": 1,
237
+ "test/motion3/verify-motion3-idle.mjs": 0.4,
238
+ "test/motion3/verify-motion3-life.mjs": 0.6,
239
+ "test/motion3/verify-motion3-load.mjs": 1.3,
240
+ "test/motion3/verify-motion3-overlap.mjs": 0.6,
241
+ "test/motion3/verify-motion3-patch-keys.mjs": 0,
242
+ "test/motion3/verify-motion3-patch.mjs": 3,
243
+ "test/motion3/verify-motion3-people.mjs": 0.7,
244
+ "test/motion3/verify-motion3-person-fix.mjs": 2.3,
245
+ "test/motion3/verify-motion3-probes.mjs": 0.4,
246
+ "test/motion3/verify-motion3-prompt.mjs": 0.1,
247
+ "test/motion3/verify-motion3-reach-human.mjs": 1.9,
248
+ "test/motion3/verify-motion3-repair.mjs": 46.3,
249
+ "test/motion3/verify-motion3-search.mjs": 8.3,
250
+ "test/motion3/verify-motion3-self.mjs": 17.2,
251
+ "test/motion3/verify-motion3-shapes.mjs": 0.1,
252
+ "test/motion3/verify-motion3-skills.mjs": 4.8,
253
+ "test/motion3/verify-motion3-socket.mjs": 9.5,
254
+ "test/motion3/verify-motion3-specstore.mjs": 6.9,
255
+ "test/motion3/verify-motion3-spring.mjs": 1.3,
256
+ "test/motion3/verify-motion3-stance-grasp.mjs": 0.8,
257
+ "test/motion3/verify-motion3-stuck.mjs": 3.1,
258
+ "test/motion3/verify-motion3-throw.mjs": 0.8,
259
+ "test/motion3/verify-motion3-timeline.mjs": 2.6,
260
+ "test/motion3/verify-motion3-timing.mjs": 0.2,
261
+ "test/motion3/verify-motion3-visual.mjs": 0.8,
262
+ "test/motion3/verify-physics-overlay.mjs": 0.6,
263
+ "test/motion3/verify-playback-frame-store.mjs": 0,
264
+ "test/process/verify-agent-deps.mjs": 1,
265
+ "test/process/verify-lifecycle.mjs": 1.6,
266
+ "test/process/verify-package-telemetry.mjs": 2,
267
+ "test/verify-agent-context-budget.mjs": 0.2,
268
+ "test/verify-agent-context-trim.mjs": 0.3,
269
+ "test/verify-agent-execution.mjs": 3.6,
270
+ "test/verify-agent-host.mjs": 0.1,
271
+ "test/verify-agent-image-references.mjs": 0.2,
272
+ "test/verify-agent-live-runtime.mjs": 0.1,
273
+ "test/verify-agent-login.mjs": 0.3,
274
+ "test/verify-agent-minimax.mjs": 0.2,
275
+ "test/verify-agent-openai-compatible.mjs": 0.3,
276
+ "test/verify-agent-panel.mjs": 0.2,
277
+ "test/verify-agent-plan-attach.mjs": 0.3,
278
+ "test/verify-agent-plan.mjs": 0.3,
279
+ "test/verify-agent-providers.mjs": 0.3,
280
+ "test/verify-agent-reply-text.mjs": 0,
281
+ "test/verify-agent-routes.mjs": 1.4,
282
+ "test/verify-agent-runner-errors.mjs": 9.8,
283
+ "test/verify-agent-script-tool.mjs": 0.4,
284
+ "test/verify-agent-sculpt-sketch.mjs": 2.6,
285
+ "test/verify-agent-sse-golden.mjs": 0.3,
286
+ "test/verify-agent-steer.mjs": 0.3,
287
+ "test/verify-agent-supervisor.mjs": 0.3,
288
+ "test/verify-agent-turn-view.mjs": 0.1,
289
+ "test/verify-analytics.mjs": 9.2,
290
+ "test/verify-animation-export.mjs": 0.1,
291
+ "test/verify-anthropic-subscription.mjs": 0.1,
292
+ "test/verify-appearance.mjs": 0,
293
+ "test/verify-asset-shelf.mjs": 0.6,
294
+ "test/verify-attachment-image.mjs": 0,
295
+ "test/verify-auto-color.mjs": 0.1,
296
+ "test/verify-beginner-screen.mjs": 0,
297
+ "test/verify-blocking-depth.mjs": 0,
298
+ "test/verify-camera-block.mjs": 0,
299
+ "test/verify-camera-direction.mjs": 0.1,
300
+ "test/verify-camera-follow.mjs": 0.1,
301
+ "test/verify-camera-move.mjs": 0,
302
+ "test/verify-camera-pointer-lock.mjs": 0,
303
+ "test/verify-camera-rail-schedule.mjs": 0,
304
+ "test/verify-canvas-commands.mjs": 0.1,
305
+ "test/verify-character-capabilities.mjs": 2.4,
306
+ "test/verify-character-group.mjs": 0.1,
307
+ "test/verify-character-kind.mjs": 0.1,
308
+ "test/verify-chinese-ui.mjs": 0.4,
309
+ "test/verify-clipboard-image.mjs": 0,
310
+ "test/verify-cliproxy-live-model.mjs": 0,
311
+ "test/verify-codex-auth.mjs": 0,
312
+ "test/verify-codex-client.mjs": 0.1,
313
+ "test/verify-coplanar-depth.mjs": 0.1,
314
+ "test/verify-cozy-scene-node.mjs": 0,
315
+ "test/verify-cuts.mjs": 0,
316
+ "test/verify-empty-object.mjs": 2.8,
317
+ "test/verify-error-boundary.mjs": 0.2,
318
+ "test/verify-execution-shared-hooks.mjs": 0.1,
319
+ "test/verify-export-capture.mjs": 0,
320
+ "test/verify-export-recovery.mjs": 3.3,
321
+ "test/verify-export-workspace.mjs": 0,
322
+ "test/verify-g006-css.mjs": 0,
323
+ "test/verify-gizmo-claim.mjs": 0,
324
+ "test/verify-grid-view.mjs": 0,
325
+ "test/verify-group-rotation.mjs": 0.1,
326
+ "test/verify-hierarchy.mjs": 0.1,
327
+ "test/verify-history.mjs": 0,
328
+ "test/verify-ik-camera-performance.mjs": 0,
329
+ "test/verify-ik-entry-camera.mjs": 0,
330
+ "test/verify-image-versions.mjs": 0,
331
+ "test/verify-keyframe-pack-request.mjs": 0,
332
+ "test/verify-keyframe-pack.mjs": 0,
333
+ "test/verify-korean-ui.mjs": 0.1,
334
+ "test/verify-label-tooltips.mjs": 0.1,
335
+ "test/verify-layout.mjs": 0.1,
336
+ "test/verify-lens-scrub.mjs": 0,
337
+ "test/verify-live-agent-commands.mjs": 0.1,
338
+ "test/verify-live-cli.mjs": 3.1,
339
+ "test/verify-live-control.mjs": 0,
340
+ "test/verify-local-placement.mjs": 0.1,
341
+ "test/verify-local-workflow.mjs": 0.1,
342
+ "test/verify-material-presets.mjs": 0.1,
343
+ "test/verify-matte-editor.mjs": 0,
344
+ "test/verify-matte.mjs": 0.1,
345
+ "test/verify-mcp-invariants.mjs": 0.1,
346
+ "test/verify-mesh-graph-clone.mjs": 0,
347
+ "test/verify-mesh-sniff.mjs": 0,
348
+ "test/verify-model-presets.mjs": 0,
349
+ "test/verify-motion-input.mjs": 0.1,
350
+ "test/verify-number-field-scrub.mjs": 0,
351
+ "test/verify-object-path.mjs": 0.1,
352
+ "test/verify-object-travel-lean.mjs": 0.1,
353
+ "test/verify-object-travel.mjs": 0.1,
354
+ "test/verify-offscreen-export.mjs": 0.1,
355
+ "test/verify-otio.mjs": 0.1,
356
+ "test/verify-package-agent-imports.mjs": 0,
357
+ "test/verify-package-signature.mjs": 0,
358
+ "test/verify-panel-stylize.mjs": 1.4,
359
+ "test/verify-part-colours.mjs": 3.6,
360
+ "test/verify-pi-tools.mjs": 0.1,
361
+ "test/verify-plan-diagram.mjs": 0.1,
362
+ "test/verify-playback-render-isolation.mjs": 0,
363
+ "test/verify-pose-fade.mjs": 0,
364
+ "test/verify-pose-gizmo.mjs": 0,
365
+ "test/verify-pose-library.mjs": 0.1,
366
+ "test/verify-project-open-file.mjs": 0.1,
367
+ "test/verify-project-previs-mode.mjs": 2.8,
368
+ "test/verify-project-resources.mjs": 0.1,
369
+ "test/verify-project.mjs": 0.2,
370
+ "test/verify-proxy-figure-bounds.mjs": 0.1,
371
+ "test/verify-proxy-figure.mjs": 0.1,
372
+ "test/verify-pwa.mjs": 0,
373
+ "test/verify-record-mp4-source.mjs": 0,
374
+ "test/verify-reference-slots.mjs": 0.1,
375
+ "test/verify-render-passes-video.mjs": 0.1,
376
+ "test/verify-render-passes.mjs": 0,
377
+ "test/verify-resilience.mjs": 0,
378
+ "test/verify-resource-status.mjs": 0.1,
379
+ "test/verify-root-path.mjs": 0.1,
380
+ "test/verify-route-owner.mjs": 0.1,
381
+ "test/verify-sample-at.mjs": 0,
382
+ "test/verify-scene-asset-cache.mjs": 0,
383
+ "test/verify-scene-assets.mjs": 0,
384
+ "test/verify-scene-mesh.mjs": 0.1,
385
+ "test/verify-scene-objects.mjs": 0.1,
386
+ "test/verify-scenes.mjs": 0.2,
387
+ "test/verify-schema-to-typebox.mjs": 0.1,
388
+ "test/verify-sculpt-blueprint.mjs": 0,
389
+ "test/verify-sculpt-compare-command.mjs": 8.4,
390
+ "test/verify-sculpt-compare.mjs": 0.9,
391
+ "test/verify-sculpt-csg.mjs": 0.3,
392
+ "test/verify-sculpt-detail.mjs": 0.9,
393
+ "test/verify-sculpt-loft-convex.mjs": 0.2,
394
+ "test/verify-sculpt-mode.mjs": 0.1,
395
+ "test/verify-sculpt-object.mjs": 3.2,
396
+ "test/verify-sculpt-panel.mjs": 0.2,
397
+ "test/verify-sculpt-recipe.mjs": 0.1,
398
+ "test/verify-sculpt-run.mjs": 0,
399
+ "test/verify-sculpt-shapes.mjs": 0.5,
400
+ "test/verify-shot-authoring.mjs": 0.1,
401
+ "test/verify-shot-cast-overrides.mjs": 1.8,
402
+ "test/verify-shot-document-v5.mjs": 0.1,
403
+ "test/verify-shot-frame.mjs": 0.1,
404
+ "test/verify-shot-guides.mjs": 0,
405
+ "test/verify-shot-look.mjs": 0,
406
+ "test/verify-shot-meta.mjs": 0,
407
+ "test/verify-shot-prompt-node.mjs": 0,
408
+ "test/verify-shot-prompt.mjs": 0,
409
+ "test/verify-speed-envelope.mjs": 0,
410
+ "test/verify-stable-ids.mjs": 0.1,
411
+ "test/verify-star-prompt.mjs": 0,
412
+ "test/verify-still-shots.mjs": 1.6,
413
+ "test/verify-storyboard.mjs": 0,
414
+ "test/verify-studio-actions.mjs": 0.1,
415
+ "test/verify-studio-agent-binding.mjs": 25.4,
416
+ "test/verify-studio-agent-geometry.mjs": 0.1,
417
+ "test/verify-studio-agent-motion.mjs": 13.3,
418
+ "test/verify-studio-agent-protocol.mjs": 0.4,
419
+ "test/verify-studio-agent-rebase.mjs": 0.3,
420
+ "test/verify-studio-agent-sampled-framing.mjs": 0.2,
421
+ "test/verify-studio-agent-tokens.mjs": 0.3,
422
+ "test/verify-studio-agent-tools.mjs": 6.3,
423
+ "test/verify-studio-agent-turn-undo.mjs": 0.1,
424
+ "test/verify-studio-contact-sheet.mjs": 0,
425
+ "test/verify-studio-elements.mjs": 0.1,
426
+ "test/verify-studio-geometry-facts.mjs": 0.1,
427
+ "test/verify-studio-owner-restart.mjs": 0.2,
428
+ "test/verify-studio-tasks.mjs": 5.1,
429
+ "test/verify-studio-undo-hygiene.mjs": 3.2,
430
+ "test/verify-task-board.mjs": 0.2,
431
+ "test/verify-telemetry-state.mjs": 0.5,
432
+ "test/verify-test-shards.mjs": 0,
433
+ "test/verify-text-object.mjs": 2.2,
434
+ "test/verify-theme.mjs": 0,
435
+ "test/verify-timeline-camera.mjs": 0.1,
436
+ "test/verify-timeline-extent.mjs": 0,
437
+ "test/verify-timeline-shots.mjs": 0.1,
438
+ "test/verify-tokens.mjs": 0,
439
+ "test/verify-tool-handlers.mjs": 0.1,
440
+ "test/verify-update-check.mjs": 0.9,
441
+ "test/verify-update-client.mjs": 0.1,
442
+ "test/verify-update-routes.mjs": 1.2,
443
+ "test/verify-usd-camera.mjs": 0.1,
444
+ "test/verify-vibe-node-schema.mjs": 0,
445
+ "test/verify-vibe-payload.mjs": 0.1,
446
+ "test/verify-video-adapters.mjs": 7.1,
447
+ "test/verify-video-contract.mjs": 0,
448
+ "test/verify-video-route.mjs": 2.1,
449
+ "test/verify-viewport-visible-rect.mjs": 0,
450
+ "test/verify-workflow-execution.mjs": 0.1,
451
+ "test/verify-workflow-resources.mjs": 0.1,
452
+ "test/verify-workflow-scene-asset-sync.mjs": 0.1,
453
+ "test/verify-workflow-send.mjs": 0.1,
454
+ "test/verify-zip-store.mjs": 0
455
+ }
@@ -0,0 +1,181 @@
1
+ // Test → file dependency graph for change-based test selection (#632).
2
+ // Each test's set is a superset of what it loads: static imports, literal
3
+ // dynamic imports, literal spawned scripts, and every string literal in a
4
+ // reached file that names an existing repository file or directory (which
5
+ // covers readFileSync(new URL("../src/x.js", import.meta.url)) and
6
+ // join(root, "src/x.js")). A test-side file whose import() or spawned script
7
+ // path cannot be read as a literal marks the test unresolved: it always runs.
8
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
9
+ import { dirname, join, normalize, relative } from "node:path";
10
+
11
+ const CODE = /\.(?:m?js|jsx|cjs)$/;
12
+ const EXTENSIONS = ["", ".js", ".jsx", ".mjs", ".cjs", "/index.js", "/index.jsx", "/index.mjs"];
13
+ const STATIC_IMPORT = /\b(?:import|export)\b[^;"'`]*?\bfrom\s*(["'])([^"'\n]+)\1|\bimport\s*(["'])([^"'\n]+)\3/g;
14
+ const DYNAMIC_IMPORT = /\bimport\(\s*([^)]*)\)/g;
15
+ const SPAWN = /\b(?:spawn|spawnSync|execFile|execFileSync|fork)\(\s*process\.execPath\s*,\s*\[([^\]]{0,300})/g;
16
+ // File reads and URLs: a path built at run time hides what the test reads, like a non-literal import().
17
+ // The argument is a lookahead, so readFileSync(new URL(...)) still yields its inner new URL( match.
18
+ const READ = /\b(?:readFileSync|readFile|createReadStream|new URL)\((?=([^\n]{0,300}))/g;
19
+ const JOINED = /\b(?:join|resolve)\(\s*[\w.$]+\s*,((?:\s*["'][^"'$\n]+["']\s*,?)+)\)/g;
20
+ const PATH_LITERAL = /(["'`])((?:\.{0,2}\/)?[\w@.-]+(?:\/[\w@.-]*)*)\1/g;
21
+ const STRING = /^\s*(["'`])([^"'`$]*)\1\s*$/;
22
+
23
+ // Repository-relative, forward slashes; null for anything outside the tree or in node_modules.
24
+ function repoPath(root, absolute) {
25
+ const path = relative(root, absolute).replaceAll("\\", "/");
26
+ return path && !path.startsWith("..") && !path.split("/").includes("node_modules") ? path : null;
27
+ }
28
+
29
+ function resolveFile(root, from, specifier) {
30
+ if (!/^(?:\.{1,2}\/|\/)/.test(specifier)) return null; // bare package or node: builtin
31
+ const base = specifier.startsWith("/") ? join(root, specifier) : join(root, dirname(from), specifier);
32
+ for (const extension of EXTENSIONS) {
33
+ const candidate = normalize(base.split("?")[0] + extension);
34
+ if (existsSync(candidate) && statSync(candidate).isFile()) return repoPath(root, candidate);
35
+ }
36
+ return null;
37
+ }
38
+
39
+ // A literal like "src/motion3/x.js", "../src/" or "./fixtures/a.json": the
40
+ // existing file or directory it names, relative to the file or to the root.
41
+ function resolveLiteral(root, from, literal) {
42
+ if (!literal.includes("/") && !/\.\w+$/.test(literal)) return null;
43
+ const bases = literal.startsWith("/") ? [join(root, literal)] : [join(root, dirname(from), literal), join(root, literal)];
44
+ for (const base of bases) {
45
+ const path = existsSync(base) ? repoPath(root, base) : null;
46
+ if (!path || path === "." ) continue;
47
+ if (statSync(base).isFile()) return { file: path };
48
+ if (path.includes("/") || literal.endsWith("/")) return { directory: `${path}/` };
49
+ }
50
+ return null;
51
+ }
52
+
53
+ // An argument is literal when it is a string, or an expression or one-level
54
+ // `const name = ...` binding whose path part is a string without `${`.
55
+ function firstElement(list) {
56
+ let depth = 0;
57
+ for (let index = 0; index < list.length; index += 1) {
58
+ if ("([{".includes(list[index])) depth += 1;
59
+ else if (")]}".includes(list[index])) depth -= 1;
60
+ if (depth < 0 || (depth === 0 && list[index] === ",")) return list.slice(0, index);
61
+ }
62
+ return list;
63
+ }
64
+
65
+ function literalArgument(source, argument, bound = false) {
66
+ const text = argument.trim();
67
+ if (!text || STRING.test(text) || /^["']-/.test(text) || text.startsWith("`data:") || text === "fileURLToPath(import.meta.url)") return true;
68
+ if (/^`[\w./-]+[?#]/.test(text)) return true; // a cache-busting query on a literal path
69
+ if (text.includes("${") || text.includes("+")) return false;
70
+ if (/["'][^"'$]+["']/.test(text)) return true;
71
+ const name = /^([A-Za-z_$][\w$]*)(?:\.href|\.pathname)?$/.exec(text)?.[1];
72
+ if (!name || name === "import") return false;
73
+ const binding = new RegExp(`\\b(?:const|let|var)\\s+${name.replace("$", "\\$")}\\s*(?:=|of)\\s*([^;\\n]+)`).exec(source);
74
+ return Boolean(binding && !bound && literalArgument(source, binding[1], true));
75
+ }
76
+
77
+ function scanFile(root, file) {
78
+ const source = readFileSync(join(root, file), "utf8");
79
+ const imports = new Set();
80
+ const files = new Set();
81
+ const directories = new Set();
82
+ let unresolved = null;
83
+ for (const match of source.matchAll(STATIC_IMPORT)) imports.add(match[2] ?? match[4]);
84
+ for (const [, argument] of source.matchAll(DYNAMIC_IMPORT)) {
85
+ const literal = STRING.exec(argument)?.[2] ?? /^\s*`([\w./-]+)[?#]/.exec(argument)?.[1];
86
+ if (literal) imports.add(literal);
87
+ else if (!literalArgument(source, argument)) unresolved ??= `import(${argument.trim().slice(0, 60)})`;
88
+ }
89
+ for (const [, list] of source.matchAll(SPAWN)) {
90
+ const argument = firstElement(list);
91
+ if (!literalArgument(source, argument)) unresolved ??= `spawn(process.execPath, [${argument.trim().slice(0, 60)}])`;
92
+ }
93
+ for (const match of source.matchAll(READ)) {
94
+ const [call, list] = match;
95
+ let argument = firstElement(list);
96
+ // readFileSync(new URL(...)) is judged by its own new URL( match; join(root, x) by its last part.
97
+ if (/^\s*new URL\(/.test(argument) || literalArgument(source, argument)) continue;
98
+ argument = /^\s*(?:join|resolve)\(\s*[\w.$]+\s*,\s*([A-Za-z_$][\w$]*)\s*\)\s*$/.exec(argument)?.[1] ?? argument;
99
+ // A bare parameter of the enclosing arrow or function (`paths.map(path => readFileSync(new URL(path, ...)))`):
100
+ // its values are the call sites' strings, which the literal scan below already records.
101
+ const name = /^\s*([A-Za-z_$][\w$]*)\s*$/.exec(argument)?.[1]?.replace("$", "\\$");
102
+ const context = source.slice(0, match.index).split("\n").slice(-4).join("\n");
103
+ if (name && new RegExp(`(?:\\b${name}\\s*=>|\\(([^()]*,\\s*)?${name}\\s*(?:,[^()]*)?\\)\\s*(?:=>|\\{))`).test(context)) continue;
104
+ // `../src/panels/${name}.jsx`, inline or in the `const` it names: the fixed directory before the first ${.
105
+ const bound = name && new RegExp(`\\bconst\\s+${name}\\s*=\\s*(\`[^\`\\n]*\`)`).exec(source.slice(0, match.index).split("\n").slice(-6).join("\n"))?.[1];
106
+ const prefix = /`([^`$]*\/)[^`/$]*\$\{/.exec(bound ?? argument)?.[1];
107
+ const directory = prefix && resolveLiteral(root, file, prefix)?.directory;
108
+ if (directory) directories.add(directory);
109
+ else unresolved ??= `${call.slice(0, call.indexOf("("))}(${argument.trim().slice(0, 60)})`;
110
+ }
111
+ for (const specifier of imports) {
112
+ const resolved = resolveFile(root, file, specifier);
113
+ if (resolved) files.add(resolved);
114
+ }
115
+ for (const [, , literal] of source.matchAll(PATH_LITERAL)) {
116
+ const resolved = resolveLiteral(root, file, literal);
117
+ if (resolved?.file) files.add(resolved.file);
118
+ else if (resolved?.directory) directories.add(resolved.directory);
119
+ }
120
+ for (const [, segments] of source.matchAll(JOINED)) {
121
+ const literal = [...segments.matchAll(/["']([^"']+)["']/g)].map((match) => match[1]).join("/");
122
+ const resolved = resolveLiteral(root, file, literal.includes("/") ? literal : `./${literal}`);
123
+ if (resolved?.file) files.add(resolved.file);
124
+ else if (resolved?.directory) directories.add(resolved.directory);
125
+ }
126
+ files.delete(file);
127
+ return { files, directories, unresolved };
128
+ }
129
+
130
+ const isTestSide = (file) => file.startsWith("test/") || /^mcp\/verify[^/]*\.mjs$/.test(file);
131
+
132
+ // Per test: every reachable file, every directory a reached file names, and
133
+ // the first non-literal load found on the test side (null when none).
134
+ export function buildGraph(root, tests) {
135
+ const scans = new Map();
136
+ const scan = (file) => {
137
+ if (!scans.has(file)) scans.set(file, CODE.test(file) ? scanFile(root, file) : { files: new Set(), directories: new Set(), unresolved: null });
138
+ return scans.get(file);
139
+ };
140
+ const graph = new Map();
141
+ for (const test of tests) {
142
+ const files = new Set([test]);
143
+ const directories = new Set();
144
+ let unresolved = null;
145
+ for (const file of files) {
146
+ const result = scan(file);
147
+ for (const next of result.files) files.add(next);
148
+ for (const directory of result.directories) directories.add(directory);
149
+ if (isTestSide(file)) unresolved ??= result.unresolved && `${file}: ${result.unresolved}`;
150
+ }
151
+ graph.set(test, { files, directories, unresolved });
152
+ }
153
+ return graph;
154
+ }
155
+
156
+ // File → tests that reach it, plus the directory entries for a prefix match.
157
+ export function reverseIndex(graph) {
158
+ const byFile = new Map();
159
+ const byDirectory = new Map();
160
+ for (const [test, { files, directories }] of graph) {
161
+ for (const file of files) byFile.set(file, [...(byFile.get(file) ?? []), test]);
162
+ for (const directory of directories) byDirectory.set(directory, [...(byDirectory.get(directory) ?? []), test]);
163
+ }
164
+ return (file) => {
165
+ const tests = new Set(byFile.get(file) ?? []);
166
+ for (const [directory, readers] of byDirectory) if (file.startsWith(directory)) for (const test of readers) tests.add(test);
167
+ return tests;
168
+ };
169
+ }
170
+
171
+ // The same `verify*.mjs` sweep tools/run-tests.mjs uses, to detect a test the
172
+ // manifest does not know about.
173
+ export function sweepVerifyFiles(root, directory) {
174
+ const absolute = join(root, directory);
175
+ if (!existsSync(absolute)) return [];
176
+ return readdirSync(absolute, { withFileTypes: true }).flatMap((entry) => {
177
+ const path = `${directory}/${entry.name}`;
178
+ if (entry.isDirectory()) return entry.name === "node_modules" ? [] : sweepVerifyFiles(root, path);
179
+ return entry.isFile() && /^verify(-.*)?\.mjs$/.test(entry.name) ? [path] : [];
180
+ });
181
+ }