@pygmalionjs/pygmalion 0.6.34 → 0.7.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 (63) hide show
  1. package/LICENSE +190 -0
  2. package/README.ko.md +309 -28
  3. package/README.md +37 -16
  4. package/dist-lib/CameraLayer-D2wrEPwG.js +415 -0
  5. package/dist-lib/frameLodRuntime-CU0IYaSu.js +272 -0
  6. package/dist-lib/pygmalion.js +11670 -16016
  7. package/dist-lib/routePreviewStatus-DTr-UJhV.js +64 -0
  8. package/dist-lib/{FrozenRoutePreview-BbF5Ov5K.js → runtime-DRkTU9eq.js} +9515 -5306
  9. package/dist-lib/testing.js +46 -6
  10. package/dist-lib/types/{App.d.ts → EditorShell.d.ts} +1 -1
  11. package/dist-lib/types/canvas/CameraLayer.d.ts +2 -1
  12. package/dist-lib/types/canvas/FrameLabelBanner.d.ts +1 -1
  13. package/dist-lib/types/canvas/FrameView.d.ts +1 -1
  14. package/dist-lib/types/canvas/FrozenRoutePreview.d.ts +1 -1
  15. package/dist-lib/types/canvas/SectionBoxes.d.ts +2 -1
  16. package/dist-lib/types/canvas/ShadowRoutePreview.d.ts +1 -1
  17. package/dist-lib/types/contract/errors.d.ts +30 -0
  18. package/dist-lib/types/contract/index.d.ts +5 -0
  19. package/dist-lib/types/contract/memoryTransport.d.ts +19 -0
  20. package/dist-lib/types/contract/paths.d.ts +57 -0
  21. package/dist-lib/types/contract/transport.d.ts +69 -0
  22. package/dist-lib/types/contract/types.d.ts +150 -0
  23. package/dist-lib/types/contract/validate.d.ts +15 -0
  24. package/dist-lib/types/contract/viteTransport.d.ts +10 -0
  25. package/dist-lib/types/core/context.d.ts +12 -0
  26. package/dist-lib/types/core/debug.d.ts +187 -0
  27. package/dist-lib/types/core/defaultRuntime.d.ts +3 -0
  28. package/dist-lib/types/core/hostBindings.d.ts +90 -0
  29. package/dist-lib/types/core/runtime.d.ts +36 -0
  30. package/dist-lib/types/core/runtimeContext.d.ts +13 -0
  31. package/dist-lib/types/editor/flowSessionScheduler.d.ts +21 -7
  32. package/dist-lib/types/editor/framePreviewKeys.d.ts +10 -10
  33. package/dist-lib/types/editor/host.d.ts +31 -26
  34. package/dist-lib/types/editor/previewBootstrap.d.ts +5 -15
  35. package/dist-lib/types/editor/previewCaptureProgress.d.ts +7 -2
  36. package/dist-lib/types/editor/projectBootGate.d.ts +17 -4
  37. package/dist-lib/types/editor/projectRuntime.d.ts +11 -95
  38. package/dist-lib/types/editor/revisionCatalog.d.ts +8 -9
  39. package/dist-lib/types/editor/scenarioCoverage.d.ts +2 -1
  40. package/dist-lib/types/editor/store.d.ts +17 -2
  41. package/dist-lib/types/editor/storyboardComposition.d.ts +1 -5
  42. package/dist-lib/types/editor/storyboardDiscovery.d.ts +6 -16
  43. package/dist-lib/types/editor/storyboardEnvironment.d.ts +2 -2
  44. package/dist-lib/types/editor/variantPrefetch.d.ts +3 -2
  45. package/dist-lib/types/editor/visualQa.d.ts +7 -2
  46. package/dist-lib/types/lib.d.ts +25 -204
  47. package/dist-lib/types/shell/ComponentStateControls.d.ts +1 -1
  48. package/dist-lib/types/testing.d.ts +5 -1
  49. package/node/component-branches.mjs +3 -3
  50. package/node/contract.d.mts +63 -0
  51. package/node/contract.mjs +175 -0
  52. package/node/design-session.mjs +4 -2
  53. package/node/dev-mirror.mjs +27 -14
  54. package/node/inspect-plugin.mjs +3 -2
  55. package/node/preview-artifact-plugin.mjs +13 -16
  56. package/node/preview-artifact-store.mjs +4 -2
  57. package/node/qa-capture-plugin.mjs +3 -2
  58. package/node/storyboard-canonical.mjs +2 -2
  59. package/node/storyboard-capture-runtime.mjs +2 -2
  60. package/node/storyboard-environment.mjs +9 -6
  61. package/node/vite.mjs +2 -13
  62. package/package.json +24 -4
  63. package/storyboard.d.ts +11 -0
package/LICENSE ADDED
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2026 Lena Jung
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
package/README.ko.md CHANGED
@@ -3,8 +3,8 @@
3
3
  [English](./README.md) | [한국어](./README.ko.md)
4
4
 
5
5
  Pygmalion은 React 애플리케이션을 위한 코드 기반 비주얼 에디터입니다. 실제
6
- DOM과 등록된 React 컴포넌트를 캔버스에 렌더링하고, 공통 컴포넌트 인스턴스를
7
- 동기화하며, 화면 편집을 검토 가능한 소스 코드 변경으로 연결합니다.
6
+ DOM과 등록된 React 컴포넌트를 캔버스에 렌더링하고 공통 컴포넌트 인스턴스를
7
+ 동기화합니다. 화면에서 편집은 검토 가능한 소스 코드 변경으로 이어집니다.
8
8
 
9
9
  > **왜 Pygmalion인가요?** 조각가가 만든 작품이 생명을 얻은 피그말리온
10
10
  > 신화에서 이름을 가져왔습니다.
@@ -20,13 +20,13 @@ DOM과 등록된 React 컴포넌트를 캔버스에 렌더링하고, 공통 컴
20
20
  - 공통 요소를 수정하면 영향을 받는 모든 프레임에 즉시 반영합니다.
21
21
  - 변경을 적용하기 전에 소스 diff와 영향받는 화면을 확인합니다.
22
22
  - 기준 화면과 변경 화면을 DOM 및 픽셀 단위로 비교합니다.
23
- - 캔버스 편집을 실행 취소하거나 다시 실행하고, 적용하지 않은 변경을 모두
23
+ - 캔버스 편집을 실행 취소하거나 다시 실행합니다. 적용하지 않은 변경은 한 번에
24
24
  초기화합니다.
25
25
 
26
26
  ## 설치
27
27
 
28
28
  Pygmalion은 공개 npm 패키지인 `@pygmalionjs/pygmalion`으로 배포합니다.
29
- 별도의 레지스트리 설정이나 인증 토큰 없이 설치할 수 있습니다.
29
+ 별도의 레지스트리 설정이나 인증 토큰은 필요하지 않습니다.
30
30
 
31
31
  ```bash
32
32
  npm install --save-dev @pygmalionjs/pygmalion
@@ -58,6 +58,7 @@ export default definePygmalionProject({
58
58
  "src/generated/design-registry.ts",
59
59
  "src/generated/design-inventory.ts",
60
60
  ],
61
+ runtimeInputs: [".env.local"],
61
62
  },
62
63
  inspect: {
63
64
  normalizeValue(property, value) {
@@ -68,8 +69,14 @@ export default definePygmalionProject({
68
69
  ```
69
70
 
70
71
  `inventory.outputs`에는 애플리케이션 루트 기준으로 생성기가 소유하는 경로만
71
- 등록합니다. Pygmalion은 전용 미러의 리비전을 전환하기 전에 이 경로만
72
- 복구하며, 밖의 변경이 있으면 기존처럼 동기화를 중단합니다.
72
+ 등록합니다. Pygmalion은 전용 미러의 리비전을 전환하기 전에 이 경로를 복구하고
73
+ 생성이 끝난 다시 확인합니다. 선언한 출력 밖에서 변경이 발견되면 동기화를
74
+ 중단합니다. Git은 무시된 파일을 보고하지 않습니다. 그래서 생성기가 건드릴 수
75
+ 있는 무시된 런타임 파일이나 설정 파일은 `inventory.runtimeInputs`에 적어
76
+ 두어야 합니다. 각 항목은 애플리케이션 루트 기준 파일 하나입니다. 최대 64개
77
+ 파일, 합계 16 MiB까지 허용합니다. Pygmalion은 생성 전후로 이 파일들의 내용을
78
+ 직접 비교합니다. `.git`, `node_modules` 같은 무관한 디렉터리는 재귀적으로 훑지
79
+ 않습니다.
73
80
 
74
81
  호스트의 Vite 설정에 통합 플러그인을 추가하세요.
75
82
 
@@ -82,14 +89,179 @@ export default defineConfig({
82
89
  });
83
90
  ```
84
91
 
92
+ JavaScript 전용 파이프라인으로 webpack 로더를 노출하는 프레임워크에서는 inspect
93
+ 로더에 소스 계측 뒤 TypeScript 제거를 요청합니다. Turbopack 규칙에서는
94
+ `transpile: true`를 켜고 원래 파일 확장자는 그대로 두세요. 그래야 상대 경로
95
+ TSX 모듈 해석이 호스트의 소스 식별자를 유지합니다.
96
+
97
+ ```ts
98
+ {
99
+ './src/**/*.tsx': {
100
+ loaders: [{
101
+ loader: require.resolve('@pygmalionjs/pygmalion/webpack-loader'),
102
+ options: { root: process.cwd(), sourceDirectory: 'src', transpile: true },
103
+ }],
104
+ },
105
+ }
106
+ ```
107
+
85
108
  미러 프리뷰가 호스트의 Vite 설정을 다시 불러올 때
86
109
  `PYGMALION_PREVIEW_MODE=1`을 사용하면 통합 플러그인이 재귀적으로 실행되지
87
110
  않습니다.
88
111
 
112
+ 미러 프리뷰와 세션 프리뷰는 각자 별도의 Vite 프로세스로 실행됩니다. 그래서
113
+ 에디터에 넘긴 mode는 그쪽까지 전달되지 않습니다. 특정 env 파일에서만 존재하는
114
+ 화면이 있다면 `preview.mode`를 지정하세요. 꺼져 있어야 하는 기능 플래그나
115
+ 레시피가 의존하는 목 프로필이 여기에 해당합니다.
116
+
117
+ ```ts
118
+ export default definePygmalionProject({
119
+ // ...
120
+ preview: { mode: "e2e" },
121
+ });
122
+ ```
123
+
124
+ ## 미러가 렌더링할 대상 바꾸기
125
+
126
+ 미러는 `source.ref`로 고정하지 않는 한 `source.branch`를 따라갑니다. 둘 다
127
+ 런타임에 다시 가리킬 수 있습니다. 두 리비전을 비교하려고 dev 서버를 재시작할
128
+ 필요가 없습니다.
129
+
130
+ ```ts
131
+ const { switchSource, mirror } = usePygmalionProject();
132
+
133
+ await switchSource("origin/dev");
134
+ await switchSource(PYGMALION_WORKTREE_SOURCE_REF); // 커밋하지 않은 작업
135
+ mirror.sourceRef; // 지금 따라가고 있는 대상
136
+ ```
137
+
138
+ `PYGMALION_WORKTREE_SOURCE_REF`는 현재 작업 트리를 일회용 커밋으로 풀어서
139
+ 렌더링합니다. 브랜치, HEAD, 인덱스는 건드리지 않습니다. 추적 중인 변경만
140
+ 포함합니다. 추적되지 않은 파일이 있으면 반환된 상태에 경고를 남깁니다.
141
+
142
+ ### 화면 선언을 선택한 리비전에 묶기
143
+
144
+ 에디터 호스트는 보통 한 번 빌드되지만 미러는 여러 체크아웃 사이를 오갑니다.
145
+ 라우팅된 페이지를 호스트에 번들하면 새 프리뷰가 옛 화면 카탈로그 아래에서
146
+ 실행되는 일이 생기죠. 미러 체크아웃마다 JSON 카탈로그를 생성하고 exact-source
147
+ 엔드포인트가 읽기 리스 아래에서 그 카탈로그를 제공하게 하세요.
148
+
149
+ ```ts
150
+ export default definePygmalionProject({
151
+ // ...
152
+ inventory: {
153
+ script: './scripts/generate-pygmalion-inventory.mjs',
154
+ outputs: ['artifacts/pygmalion-revision-catalog.json'],
155
+ },
156
+ preview: {
157
+ catalog: { file: 'artifacts/pygmalion-revision-catalog.json' },
158
+ },
159
+ });
160
+ ```
161
+
162
+ 기본 `inventory.script` 호출에서 Pygmalion은
163
+ `--source-root <path> --out-root <path> --commit <sha>`를 넘깁니다. 생성기의
164
+ CLI 형태가 다르면 `inventory.args(context)`를 직접 정의하세요. 이때도 같은
165
+ `context.commit`을 받습니다.
166
+
167
+ 생성된 파일은 `PygmalionRevisionCatalog`로 export되는 버전 있는 JSON 전용
168
+ 계약을 따릅니다. 인벤토리 생성기의 `commit` 컨텍스트로 `sourceRevision`을
169
+ 기록하세요. 라우팅된 `screens.pages`와 `screens.assets`, `tokens`, 그리고
170
+ 리비전마다 달라질 수 있는 모든 화면 선언을 포함합니다. 직렬화 가능한
171
+ 레지스트리 메타데이터는 `componentRegistry`에 넣습니다. 에디터는 이
172
+ 메타데이터를 이름으로 호스트가 이미 번들한 React 구현에 연결합니다. 구현이 없는
173
+ 카탈로그는 거부합니다. 이렇게 하면 JSON에 함수를 넣지 않고도 props, 기본값,
174
+ 채택 정보, 코드 생성 메타데이터가 리비전에 묶입니다. 저장소가 소유하는 생성
175
+ 코드 의도는 `codegenProject`에 두세요. 그러면 프레임 계약과 프롬프트 출처가 같은
176
+ 카탈로그와 함께 전환됩니다. 그런 다음 에디터의 transport에서 정확한 프리뷰
177
+ 서비스를 켭니다.
178
+
179
+ ```tsx
180
+ // Once, for the editor's lifetime. The catalog endpoint derives from the
181
+ // artifact endpoint; pass `previewCatalog: null` to run artifacts alone.
182
+ const transport = createViteTransport({ endpoints: { previewArtifact: true } });
183
+ const runtime = createEditorRuntime({ transport });
184
+
185
+ function Editor() {
186
+ const { appOrigin, previewRevision } = usePygmalionProject({ transport });
187
+ return (
188
+ <PygmalionEditor
189
+ runtime={runtime}
190
+ previewCacheNamespace="my-product"
191
+ previewRevision={previewRevision}
192
+ appOrigin={appOrigin ?? undefined}
193
+ />
194
+ );
195
+ }
196
+ ```
197
+
198
+ 에디터와 프로젝트 훅이 보내는 모든 요청은 이 transport를 거칩니다. 둘이 같은
199
+ 서비스와 대화하는 셈이죠. 연산과 경로와 오류 목록은
200
+ [The editor transport](./docs/transport.md)에 정리했습니다. 훅이 돌려주는
201
+ `previewRevision`을 전체 그대로 넘기세요. 에디터는 카탈로그 요청에 쓸 소스
202
+ SHA를 여기서 뽑아냅니다. 화면 캐시 무효화에 쓰는 세션 변경 카운터는 그대로
203
+ 유지합니다.
204
+
205
+ 에디터는 설치 전에 네임스페이스와 소스 리비전을 모두 검증합니다. 다른
206
+ 체크아웃이 준비되는 동안에는 마지막으로 완성된 카탈로그, 프리뷰 origin, 상호작용
207
+ 선언을 한 묶음으로 유지합니다. dev → qa → dev 순서로 요청했을 때 앞선 요청의
208
+ 늦은 응답이 현재 선택을 덮어쓰지 못합니다. 잘못된 카탈로그, 영구히 사용할 수
209
+ 없는 카탈로그, 설치 가능한 페이지가 하나도 없는 카탈로그는 전용 오류 화면을
210
+ 띄우고 설치를 중단합니다. 이전 캔버스를 요청한 리비전인 것처럼 표시하는 일은
211
+ 없습니다. 라우팅된 화면이 없는 카탈로그라도 호스트가 화면이 아닌 라이브러리
212
+ 페이지를 제공하면 설치됩니다.
213
+
214
+ `onDesignChange`가 연결되어 있으면 각 payload에 편집 배치를 소유한 정확한
215
+ `sourceRevision`이 실립니다. 열거되지 않는(non-enumerable) `signal` 속성은
216
+ 해당 카탈로그가 퇴역할 때 중단됩니다. 프로세스 안에서 실행되는 호스트 어댑터는
217
+ 기존 JSON 요청 본문을 바꾸지 않고도 이 신호로 작업을 취소합니다.
218
+
219
+ ref 문자열을 물어보는 대신 선택지를 보여 주고 싶다면 리비전 목록을 가져와
220
+ 제공되는 컨트롤을 툴바에 렌더링하세요.
221
+
222
+ ```tsx
223
+ const { sourceRefs, switchSource, mirror } = usePygmalionProject();
224
+
225
+ <SourceRefControl
226
+ value={mirror.sourceRef}
227
+ currentCommit={mirror.shortCommit}
228
+ refs={sourceRefs.refs}
229
+ defaultRef={sourceRefs.defaultRef}
230
+ worktreeRef={sourceRefs.worktreeRef}
231
+ busy={mirror.state === 'syncing'}
232
+ refreshLabel="Refresh this branch"
233
+ onChange={(ref) => void switchSource(ref)}
234
+ >
235
+ {/* 선택: 툴바의 일부처럼 보이도록 직접 만든 트리거 */}
236
+ <span>{mirror.sourceRef ?? 'dev'}@{mirror.shortCommit}</span>
237
+ </SourceRefControl>;
238
+ ```
239
+
240
+ 메뉴는 그 트리거 위에 겹쳐진 네이티브 select입니다. 키보드 접근성, 모바일 동작,
241
+ 배치는 플랫폼이 맡습니다. 그려진 트리거는 호스트 코드가 그대로 소유합니다. 첫
242
+ 항목은 선택한 리비전을 명시적으로 다시 불러옵니다. 같은 브랜치를 선택한 채로
243
+ 브랜치의 최신 커밋이 바뀐 경우도 포함됩니다. `currentCommit`을 넘기면 목록에 더
244
+ 새로운 ref가 있을 때 컨트롤에 `[data-update-available]`과
245
+ `[data-latest-commit]`이 표시됩니다. 스타일링에는 `[data-pygmalion-source-ref]`와
246
+ `[data-busy]`도 쓸 수 있습니다.
247
+
248
+ 이 목록은 `GET /__pygmalion-dev-control/refs`가 뒷받침합니다. 로컬 브랜치, 원격
249
+ 추적 브랜치, 기본 리비전, 워크트리 ref를 돌려주죠. 브랜치가 바뀐 뒤에는
250
+ `loadSourceRefs()`로 다시 불러옵니다.
251
+
252
+ 프리뷰 산출물은 소스 SHA별로 캐시됩니다. 전환하면 그 캐시는 무효화되고 다음
253
+ 캡처는 처음부터 다시 실행됩니다. 이전 리비전을 위해 이미 실행 중이던 캡처는
254
+ 발행되지 않고 버려집니다. 그래서 에디터가 옮겨 간 산출물을 덮어쓰지 못합니다.
255
+
256
+ 디자인 세션의 워크트리는 소스 SHA 하나에서 분기됩니다. 적용하지 않은 편집이
257
+ 남아 있으면 `switchSource`는 거부합니다. 그 편집이 작성된 적 없는 리비전 위에
258
+ 캔버스를 두지 않기 위해서입니다. 먼저 적용하거나 되돌리세요. 아니면
259
+ `{ discardEdits: true }`를 넘기면 됩니다.
260
+
89
261
  ## 지원하는 폭에서 프레임 확인하기
90
262
 
91
263
  프레임은 모서리를 끌거나 W/H 입력으로 크기를 바꿉니다. 여기에 애플리케이션이
92
- 실제로 보장하는 폭에 이름을 붙여 두면, 그 입력 옆에 버튼으로 놓입니다. 숫자를
264
+ 실제로 보장하는 폭에 이름을 붙여 두면 그 입력 옆에 버튼으로 놓입니다. 숫자를
93
265
  외우지 않아도 폭 사이를 오갈 수 있습니다.
94
266
 
95
267
  ```tsx
@@ -102,8 +274,35 @@ export default defineConfig({
102
274
  ```
103
275
 
104
276
  `height`를 빼면 폭만 바꾸고 높이는 그대로 둡니다. 프레임이 그 크기에 있는 동안
105
- 버튼은 눌린 상태로 보이고, **Reset to default size**는 여전히 매니페스트가 선언한
106
- 뷰포트로 되돌립니다.
277
+ 버튼은 눌린 상태로 보입니다. **Reset to default size**는 여전히 매니페스트가
278
+ 선언한 뷰포트로 되돌립니다.
279
+
280
+ 첫 번째로 선언된 캔버스가 큰 에셋 카탈로그라면 작업 캔버스를 바로 여세요. 시작
281
+ 시점에 그 카탈로그를 렌더링하지 않습니다.
282
+
283
+ ```tsx
284
+ <PygmalionEditor initialCanvas="Screens" />
285
+ ```
286
+
287
+ ### 멈추지 않는 화면
288
+
289
+ 캡처는 문서가 가만히 멈추길 기다립니다. 경과 시간 시계, 레벨 미터, 마키가 있는
290
+ 화면은 절대 멈추지 않으므로 아무리 기다려도 `stabilize` 단계에서 실패하죠. 그런
291
+ 영역을 선언해 두면 그 안의 변화는 더 이상 변경으로 집계되지 않습니다.
292
+
293
+ ```ts
294
+ captureStoryboardCase({
295
+ // ...
296
+ stability: {
297
+ volatileSelectors: ['[data-testid="elapsed-time"]', '[data-live-meter]'],
298
+ },
299
+ });
300
+ ```
301
+
302
+ 대기는 100ms마다 표본을 뽑아 같은 표본이 세 번 연속 나오면 끝납니다. 상한은
303
+ 4초입니다. 1초 간격으로 다시 그려지는 화면에도 충분한 폭입니다. 그보다 느린
304
+ 화면은 `attempts`, `requiredStableSamples`, `intervalMs`, `minimumWaitMs`로
305
+ 조정합니다.
107
306
 
108
307
  ## 화면과 시나리오 등록
109
308
 
@@ -120,33 +319,101 @@ export default defineConfig({
120
319
  하나의 시나리오는 반드시 한 분류에만 속해야 합니다. 잘못된 참조, 누락된
121
320
  시나리오, 중복 분류가 있으면 에디터를 열기 전에 검증이 실패합니다.
122
321
 
123
- 화면 레시피는 `click`, `fill`, `check`, `press`, `wait`, `storage` 단계를
124
- 지원합니다. 프레임이 항상 같은 애플리케이션 상태를 재현하도록 결정적인
125
- 레시피와 assertion을 사용하세요.
322
+ 화면 레시피는 `click`, `focus`, `hover`, `focus-visible`, `active`, `fill`,
323
+ `check`, `press`, `scroll`, `wait`, `storage` 단계를 지원합니다. 프레임이 항상
324
+ 같은 애플리케이션 상태를 재현하도록 결정적인 레시피와 assertion을 사용하세요.
325
+ 어떤 변형이 프레임인지, 상호작용 상태인지, 조건 상태인지, 편집 가능한
326
+ 매개변수인지, 모션 프리뷰인지, 동작 전용 QA인지는
327
+ [화면 상태 계약](./docs/screen-state-contract.md)이 정의합니다. 렌더링된 CSS와
328
+ Web Animations 대상은 오른쪽 패널의 Motion 컨트롤에 자동으로 나타납니다. 재생,
329
+ 일시 정지, 초기화, 대상 격리, 단계 스크러빙을 지원합니다.
126
330
 
127
- ## 캡처 산출물 생명주기
331
+ ### 제품 라우트와 프리뷰 진입 라우트 분리하기
332
+
333
+ 인증과 fixture 게이트웨이는 호스트 애플리케이션이 소유합니다. 화면에 게이트웨이가
334
+ 필요하면 `route`는 정식 제품 주소로 두고 라우팅된 게이트웨이는 `previewRoute`로
335
+ 선언하세요.
336
+
337
+ ```ts
338
+ {
339
+ id: 'screen:account-security',
340
+ name: 'Account security',
341
+ section: 'Account',
342
+ route: '/account/security',
343
+ previewRoute: '/__preview__/account/security',
344
+ }
345
+ ```
128
346
 
129
- 범용 캡처 기능은 `@pygmalionjs/pygmalion/storyboard`에서 가져옵니다.
130
- Pygmalion은 격리된 브라우저 컨텍스트, 제한된 병렬 스케줄링, 비활성 DOM
131
- 스냅샷, 스크린샷, QA 진단, 압축된 버전 산출물, 정확한 리비전 검증, 원자적
132
- 산출물 교체를 관리합니다. Vite 통합은 현재 에디터의 namespace와 소스
133
- 리비전에 정확히 일치하는 산출물만 제공합니다.
347
+ Pygmalion은 `previewRoute`로 부팅, 캡처, 캐시, 상호작용을 수행합니다. 인벤토리,
348
+ 커버리지, 소스 식별자에는 계속 `route`를 사용합니다. 게이트웨이는 개발 전용이어야
349
+ 합니다. 자격 증명을 URL이나 클라이언트 매니페스트에 넣지 마세요. 별도로 조립한
350
+ 컴포넌트 fixture 대신 실제 라우팅된 화면을 렌더링하거나 그쪽으로 리디렉션해야
351
+ 합니다. 게이트웨이를 바꾸면 프레임의 프리뷰 캐시는 자동으로 무효화됩니다.
134
352
 
135
- 호스트 애플리케이션은 라우트, 환경 preset, 어댑터, 상호작용 recipe,
136
- assertion만 제공합니다. 도메인별 네트워크 fixture는 호스트 hook에서 설치할
137
- 있지만 브라우저나 산출물 생명주기를 별도로 구현하면 안 됩니다.
353
+ 선언한 `screenFlows`도 같은 분리를 지원합니다. 정식 시작 주소는 `route`에, 호스트
354
+ 게이트웨이는 `previewRoute`에 두세요. 플로는 게이트웨이로 부팅하되 캡처 준비에는
355
+ 정식 라우트를 보고합니다.
138
356
 
139
- 산출물 v3는 등록한 모든 프레임을 `ready`,
140
- `rendered-with-qa-failure`, `capture-error` 하나로 보존합니다. QA 실패는
141
- CI를 실패 상태로 유지하면서 마지막으로 안정화된 DOM과 스크린샷을 남길 수
142
- 있습니다. 따라서 엄격 캡처가 실패해도 이전 리비전의 산출물이 조용히 계속
143
- 활성화되지 않습니다.
357
+ 소스 내비게이션 추론에만 의존하지 말고 사용자 여정을 명시적으로 유지하세요. 경로는
358
+ 이웃한 그래프 간선으로 확장됩니다. 소스에서 발견된 간선은 그 아래에 계속
359
+ 병합됩니다.
360
+
361
+ ```tsx
362
+ const storyboard = {
363
+ startScreenIds: ['screen:entry'],
364
+ paths: [
365
+ {
366
+ id: 'checkout',
367
+ label: 'Checkout',
368
+ screenIds: ['screen:entry', 'screen:cart', 'screen:confirmation'],
369
+ },
370
+ ],
371
+ };
372
+
373
+ <PygmalionEditor storyboard={storyboard} />
374
+ ```
375
+
376
+ 모든 id는 해석된 화면 카탈로그와 대조합니다. 알 수 없는 끝점과 도달할 수 없는
377
+ 화면은 사이드바에서 사라지는 대신 그래프 진단으로 남습니다. 코드 전용
378
+ 리디렉션이나 fixture는 `createStoryboardRouteScenarioId(route)`로 만든 id를
379
+ `nonVisualScenarioIds`에 넣어 분류합니다.
380
+
381
+ 에디터 셸과 프레임 배치는 스토리보드 탐색이 끝나기 전에 마운트됩니다. 캐시된
382
+ 라우트 콘텐츠와 라이브 라우트 콘텐츠는 기준 환경과 소스 다이제스트가 확정될
383
+ 때까지 막혀 있습니다. 그래서 먼저 그려진 캔버스가 임시 프리뷰 식별자를 쓰는 일은
384
+ 없습니다. 이미 보이는 프레임을 사이드바에서 선택하면 카메라는 그대로입니다. 화면
385
+ 밖에 있는 프레임은 최소한의 이동으로 보이게 하고 사용자의 줌은 바꾸지 않습니다.
386
+
387
+ ## 캡처 산출물 생명주기
388
+
389
+ 재사용 가능한 캡처 기능은 `@pygmalionjs/pygmalion/storyboard`에서 가져옵니다.
390
+ Pygmalion은 격리된 브라우저 컨텍스트, 제한된 병렬 스케줄링, 비활성 DOM 스냅샷,
391
+ 스크린샷, QA 진단, 압축된 버전 산출물, 정확한 리비전 검증, 원자적 산출물 발행을
392
+ 관리합니다. Vite 통합은 현재 에디터의 네임스페이스와 소스 리비전에 정확히
393
+ 일치하는 산출물만 제공합니다.
394
+
395
+ 호스트 애플리케이션은 라우트, 환경 preset, 목 어댑터, 상호작용 레시피,
396
+ assertion을 제공합니다. 도메인별 네트워크 fixture는 호스트 hook에서 설치할 수
397
+ 있지만 브라우저나 산출물 생명주기를 별도로 구현하면 안 됩니다.
398
+
399
+ 산출물 v3는 등록한 모든 프레임을 `ready`, `rendered-with-qa-failure`,
400
+ `capture-error` 중 하나의 명시적 결과로 보존합니다. QA 실패는 CI를 실패 상태로
401
+ 유지하면서 마지막으로 안정화된 DOM과 스크린샷을 남깁니다. 따라서 엄격 캡처가
402
+ 실패해도 이전 산출물이 조용히 계속 활성화되지 않습니다.
403
+
404
+ transport에 프리뷰 산출물 엔드포인트가 설정되어 있으면 네임스페이스나 소스
405
+ 리비전이 다른 내장 산출물은 눈에 띄게 오래된 마지막 프리뷰로만 취급됩니다. 이 산출물은
406
+ `data-preview-warm`에 포함되지 않습니다. 각 프레임은 정확한 해석의 생명주기를
407
+ `data-artifact-resolution`으로 드러냅니다. 값은 `checking`, `outdated`,
408
+ `generating`, `error`, `exact` 중 하나입니다. 전송, 검증, 생성 실패는 프레임에
409
+ 재시도 동작과 함께 남습니다. 최신 라이브 스냅샷이나 정확한 엔드포인트 응답이
410
+ 오면 오래된 상태가 해소됩니다.
144
411
 
145
412
  ## 편집 흐름
146
413
 
147
414
  **Icons**, **Atoms**, **Components**에서 항목을 선택하면 해당 카탈로그
148
415
  프레임으로 이동해 소스 구현 레이어를 자동으로 선택합니다. 행 오른쪽의 `+`는
149
- 삽입 전용이므로, 자산을 열기만 해서는 다른 프레임을 변경하지 않습니다.
416
+ 삽입 전용이므로 에셋을 열기만 해서는 다른 프레임을 변경하지 않습니다.
150
417
 
151
418
  1. **Screens**를 엽니다. 프레임을 클릭하지 않아도 프리뷰 준비를 시작합니다.
152
419
  2. 사이드바에서 프레임을 선택해 캔버스 중앙으로 이동합니다.
@@ -171,6 +438,7 @@ npm run dev
171
438
  검증 명령:
172
439
 
173
440
  ```bash
441
+ npm run lint
174
442
  npm test
175
443
  npm run typecheck
176
444
  npm run build:lib
@@ -180,7 +448,20 @@ npm run lint:language
180
448
  ## 프로젝트 문서
181
449
 
182
450
  - [Architecture](./ARCHITECTURE.md): 패키지와 호스트의 경계를 정의합니다.
451
+ - [Design compiler and component connections](./docs/design-compiler.md): 버전
452
+ 있는 IR, 대상 어댑터, 진단, 외부 디자인 매핑을 정의합니다.
453
+ - [Screen state contract](./docs/screen-state-contract.md): 프레임과 같은
454
+ 프레임 안의 배치를 구분합니다. 유지된 pseudo 상태 캡처도 여기서 정의합니다.
183
455
  - [Editor usability](./EDITOR-USABILITY.md): 에디터 상호작용의 지원 범위를
184
456
  정의합니다.
185
457
  - [Product readiness](./PRODUCTIZATION.md): 품질 기준과 남은 작업을 정의합니다.
186
- - [Contributing](./CONTRIBUTING.md): 필수 커밋 형식을 정의합니다.
458
+ - [The editor transport](./docs/transport.md): 모든 요청이 거치는 하나의
459
+ 객체를 정의합니다. 엔드포인트 표와 오류 모델도 여기에 있습니다.
460
+ - [Upgrading to 0.7](./docs/migration-0.7.md): 사라진 모듈 수준 export를
461
+ 에디터 런타임으로, 사라진 엔드포인트 prop을 transport로 대응시킵니다.
462
+ - [Contributing](./CONTRIBUTING.md): 필수 커밋 형식과 릴리스 절차를 정의합니다.
463
+ - [Changelog](./CHANGELOG.md): 발행된 각 버전이 무엇을 바꿨는지 기록합니다.
464
+
465
+ ## 라이선스
466
+
467
+ Pygmalion은 [Apache License 2.0](./LICENSE)으로 배포합니다.