@ait-co/devtools 0.1.143 → 0.2.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 (223) hide show
  1. package/README.en.md +65 -163
  2. package/README.md +65 -192
  3. package/dist/in-app/auto.d.ts +1 -138
  4. package/dist/in-app/auto.js +28 -1102
  5. package/dist/in-app/auto.js.map +1 -1
  6. package/dist/in-app/index.d.ts +38 -547
  7. package/dist/in-app/index.d.ts.map +1 -1
  8. package/dist/in-app/index.js +62 -939
  9. package/dist/in-app/index.js.map +1 -1
  10. package/dist/mcp/cli.d.ts +1 -54
  11. package/dist/mcp/cli.js +33 -9720
  12. package/dist/mcp/cli.js.map +1 -1
  13. package/dist/mcp/server.d.ts +1 -88
  14. package/dist/mcp/server.js +36 -1076
  15. package/dist/mcp/server.js.map +1 -1
  16. package/dist/mock/index.d.ts +19 -20
  17. package/dist/mock/index.d.ts.map +1 -1
  18. package/dist/mock/index.js.map +1 -1
  19. package/dist/optional-peers-CDEFhlhJ.cjs +131 -0
  20. package/dist/optional-peers-CDEFhlhJ.cjs.map +1 -0
  21. package/dist/optional-peers-FdVbUJst.js +96 -0
  22. package/dist/optional-peers-FdVbUJst.js.map +1 -0
  23. package/dist/panel/index.js +1 -103
  24. package/dist/panel/index.js.map +1 -1
  25. package/dist/relay-url-store-CPZAn-T5.js +107 -0
  26. package/dist/relay-url-store-CPZAn-T5.js.map +1 -0
  27. package/dist/relay-url-store-DLjlvMSA.cjs +108 -0
  28. package/dist/relay-url-store-DLjlvMSA.cjs.map +1 -0
  29. package/dist/stubs/bin-devtools-mcp.js +58 -0
  30. package/dist/stubs/bin-devtools-mcp.js.map +1 -0
  31. package/dist/stubs/bin-devtools-test.d.ts +2 -0
  32. package/dist/stubs/bin-devtools-test.js +55 -0
  33. package/dist/stubs/bin-devtools-test.js.map +1 -0
  34. package/dist/test-runner/config.d.ts +1 -231
  35. package/dist/test-runner/config.js +41 -45
  36. package/dist/test-runner/config.js.map +1 -1
  37. package/dist/{tunnel-BVSMXctM.cjs → tunnel-BKZkOyQp.cjs} +27 -75
  38. package/dist/tunnel-BKZkOyQp.cjs.map +1 -0
  39. package/dist/{tunnel-D7xkimBu.js → tunnel-CqSCIrdU.js} +27 -75
  40. package/dist/tunnel-CqSCIrdU.js.map +1 -0
  41. package/dist/unplugin/index.cjs +17 -30
  42. package/dist/unplugin/index.cjs.map +1 -1
  43. package/dist/unplugin/index.d.cts +34 -5
  44. package/dist/unplugin/index.d.cts.map +1 -1
  45. package/dist/unplugin/index.d.ts +35 -6
  46. package/dist/unplugin/index.d.ts.map +1 -1
  47. package/dist/unplugin/index.js +17 -30
  48. package/dist/unplugin/index.js.map +1 -1
  49. package/dist/unplugin/tunnel.cjs +61 -74
  50. package/dist/unplugin/tunnel.cjs.map +1 -1
  51. package/dist/unplugin/tunnel.d.cts +22 -16
  52. package/dist/unplugin/tunnel.d.cts.map +1 -1
  53. package/dist/unplugin/tunnel.d.ts +22 -16
  54. package/dist/unplugin/tunnel.d.ts.map +1 -1
  55. package/dist/unplugin/tunnel.js +61 -74
  56. package/dist/unplugin/tunnel.js.map +1 -1
  57. package/package.json +17 -22
  58. package/dist/attach-orchestrator-0F0m_UqQ.js +0 -1845
  59. package/dist/attach-orchestrator-0F0m_UqQ.js.map +0 -1
  60. package/dist/attach-orchestrator-D65KxFy_.js +0 -1831
  61. package/dist/attach-orchestrator-D65KxFy_.js.map +0 -1
  62. package/dist/attach-orchestrator-DL3NQ9ca.js +0 -1846
  63. package/dist/attach-orchestrator-DL3NQ9ca.js.map +0 -1
  64. package/dist/bundle-C796JIwG.d.ts +0 -159
  65. package/dist/bundle-C796JIwG.d.ts.map +0 -1
  66. package/dist/capture-DsP525OZ.d.ts +0 -58
  67. package/dist/capture-DsP525OZ.d.ts.map +0 -1
  68. package/dist/cdp-connection-rP1WdnH5.d.ts +0 -287
  69. package/dist/cdp-connection-rP1WdnH5.d.ts.map +0 -1
  70. package/dist/cell-BaLvusOl.js +0 -68
  71. package/dist/cell-BaLvusOl.js.map +0 -1
  72. package/dist/cell-CBUS3-nT.js +0 -274
  73. package/dist/cell-CBUS3-nT.js.map +0 -1
  74. package/dist/cell-EBKKpAAT.js +0 -307
  75. package/dist/cell-EBKKpAAT.js.map +0 -1
  76. package/dist/chii-relay-BZ3HqWL5.js +0 -304
  77. package/dist/chii-relay-BZ3HqWL5.js.map +0 -1
  78. package/dist/chii-relay-D7eK2acz.cjs +0 -304
  79. package/dist/chii-relay-D7eK2acz.cjs.map +0 -1
  80. package/dist/debug-server-B3ABDrRI.js +0 -456
  81. package/dist/debug-server-B3ABDrRI.js.map +0 -1
  82. package/dist/debug-server-BWhwrVXa.js +0 -1158
  83. package/dist/debug-server-BWhwrVXa.js.map +0 -1
  84. package/dist/debug-server-CfQNxxGW.js +0 -600
  85. package/dist/debug-server-CfQNxxGW.js.map +0 -1
  86. package/dist/deeplink-B5-Hxu0Q.js +0 -62
  87. package/dist/deeplink-B5-Hxu0Q.js.map +0 -1
  88. package/dist/deeplink-BpO9qc-D.js +0 -62
  89. package/dist/deeplink-BpO9qc-D.js.map +0 -1
  90. package/dist/deeplink-BzdbA1gV.cjs +0 -62
  91. package/dist/deeplink-BzdbA1gV.cjs.map +0 -1
  92. package/dist/deeplink-DCScMYcp.cjs +0 -62
  93. package/dist/deeplink-DCScMYcp.cjs.map +0 -1
  94. package/dist/devtools-opener-3Drge_RJ.js +0 -75
  95. package/dist/devtools-opener-3Drge_RJ.js.map +0 -1
  96. package/dist/devtools-opener-B8nxrxqu.js +0 -71
  97. package/dist/devtools-opener-B8nxrxqu.js.map +0 -1
  98. package/dist/devtools-opener-BDY0w3_0.cjs +0 -68
  99. package/dist/devtools-opener-BDY0w3_0.cjs.map +0 -1
  100. package/dist/devtools-opener-BTl5A6Cd.js +0 -71
  101. package/dist/devtools-opener-BTl5A6Cd.js.map +0 -1
  102. package/dist/devtools-opener-CJpEsXXQ.js +0 -76
  103. package/dist/devtools-opener-CJpEsXXQ.js.map +0 -1
  104. package/dist/devtools-opener-CxtryS8c.js +0 -75
  105. package/dist/devtools-opener-CxtryS8c.js.map +0 -1
  106. package/dist/devtools-opener-iv1OwfJN.cjs +0 -68
  107. package/dist/devtools-opener-iv1OwfJN.cjs.map +0 -1
  108. package/dist/in-app/auto.d.ts.map +0 -1
  109. package/dist/mcp/cli.d.ts.map +0 -1
  110. package/dist/mcp/server.d.ts.map +0 -1
  111. package/dist/pool-DcaaOwUq.d.ts +0 -14761
  112. package/dist/pool-DcaaOwUq.d.ts.map +0 -1
  113. package/dist/qr-http-server--gl2-WKc.cjs +0 -1644
  114. package/dist/qr-http-server--gl2-WKc.cjs.map +0 -1
  115. package/dist/qr-http-server-Bb7lMeqi.js +0 -1644
  116. package/dist/qr-http-server-Bb7lMeqi.js.map +0 -1
  117. package/dist/qr-http-server-C_lqOrgc.js +0 -1644
  118. package/dist/qr-http-server-C_lqOrgc.js.map +0 -1
  119. package/dist/qr-http-server-CopuMbub.js +0 -1644
  120. package/dist/qr-http-server-CopuMbub.js.map +0 -1
  121. package/dist/qr-http-server-D-Off6K1.cjs +0 -1644
  122. package/dist/qr-http-server-D-Off6K1.cjs.map +0 -1
  123. package/dist/qr-http-server-DrbIVDjO.js +0 -1645
  124. package/dist/qr-http-server-DrbIVDjO.js.map +0 -1
  125. package/dist/qr-http-server-n1twN18z.js +0 -1644
  126. package/dist/qr-http-server-n1twN18z.js.map +0 -1
  127. package/dist/relay-factory-N9QobQxG.js +0 -206
  128. package/dist/relay-factory-N9QobQxG.js.map +0 -1
  129. package/dist/relay-secret-store-BPhN1upr.js +0 -240
  130. package/dist/relay-secret-store-BPhN1upr.js.map +0 -1
  131. package/dist/relay-secret-store-Bmyleu0A.js +0 -154
  132. package/dist/relay-secret-store-Bmyleu0A.js.map +0 -1
  133. package/dist/relay-secret-store-CQenfcSL.js +0 -154
  134. package/dist/relay-secret-store-CQenfcSL.js.map +0 -1
  135. package/dist/relay-secret-store-DKxs7zwq.js +0 -153
  136. package/dist/relay-secret-store-DKxs7zwq.js.map +0 -1
  137. package/dist/relay-secret-store-DWKdV-eY.cjs +0 -241
  138. package/dist/relay-secret-store-DWKdV-eY.cjs.map +0 -1
  139. package/dist/relay-secret-store-WJ8EGkIl.js +0 -153
  140. package/dist/relay-secret-store-WJ8EGkIl.js.map +0 -1
  141. package/dist/relay-url-store-1FGuSYAn.cjs +0 -115
  142. package/dist/relay-url-store-1FGuSYAn.cjs.map +0 -1
  143. package/dist/relay-url-store-BR2XodiO.js +0 -123
  144. package/dist/relay-url-store-BR2XodiO.js.map +0 -1
  145. package/dist/relay-url-store-Bskcyeg8.js +0 -114
  146. package/dist/relay-url-store-Bskcyeg8.js.map +0 -1
  147. package/dist/relay-url-store-CH63fVCm.js +0 -122
  148. package/dist/relay-url-store-CH63fVCm.js.map +0 -1
  149. package/dist/relay-url-store-DaY1QPes.js +0 -123
  150. package/dist/relay-url-store-DaY1QPes.js.map +0 -1
  151. package/dist/relay-url-store-xmUuTjXA.js +0 -122
  152. package/dist/relay-url-store-xmUuTjXA.js.map +0 -1
  153. package/dist/relay-worker-B5HKkGUY.js +0 -832
  154. package/dist/relay-worker-B5HKkGUY.js.map +0 -1
  155. package/dist/relay-worker-YdlpZQl9.d.ts +0 -214
  156. package/dist/relay-worker-YdlpZQl9.d.ts.map +0 -1
  157. package/dist/rolldown-runtime-DGkTqVfb.js +0 -15
  158. package/dist/rolldown-runtime-DUslC3ob.js +0 -14
  159. package/dist/runtime-kn9DxOeg.d.ts +0 -249
  160. package/dist/runtime-kn9DxOeg.d.ts.map +0 -1
  161. package/dist/test-runner/bin.js +0 -2584
  162. package/dist/test-runner/bin.js.map +0 -1
  163. package/dist/test-runner/bridge-stub.d.ts +0 -125
  164. package/dist/test-runner/bridge-stub.d.ts.map +0 -1
  165. package/dist/test-runner/bridge-stub.js +0 -92
  166. package/dist/test-runner/bridge-stub.js.map +0 -1
  167. package/dist/test-runner/bundle.d.ts +0 -2
  168. package/dist/test-runner/bundle.js +0 -439
  169. package/dist/test-runner/bundle.js.map +0 -1
  170. package/dist/test-runner/capture.d.ts +0 -2
  171. package/dist/test-runner/capture.js +0 -44
  172. package/dist/test-runner/capture.js.map +0 -1
  173. package/dist/test-runner/config.d.ts.map +0 -1
  174. package/dist/test-runner/method-pace.d.ts +0 -82
  175. package/dist/test-runner/method-pace.d.ts.map +0 -1
  176. package/dist/test-runner/method-pace.js +0 -120
  177. package/dist/test-runner/method-pace.js.map +0 -1
  178. package/dist/test-runner/pool.d.ts +0 -2
  179. package/dist/test-runner/pool.js +0 -136
  180. package/dist/test-runner/pool.js.map +0 -1
  181. package/dist/test-runner/relay-factory.d.ts +0 -11245
  182. package/dist/test-runner/relay-factory.d.ts.map +0 -1
  183. package/dist/test-runner/relay-factory.js +0 -206
  184. package/dist/test-runner/relay-factory.js.map +0 -1
  185. package/dist/test-runner/relay-worker.d.ts +0 -2
  186. package/dist/test-runner/relay-worker.js +0 -2
  187. package/dist/test-runner/report.d.ts +0 -163
  188. package/dist/test-runner/report.d.ts.map +0 -1
  189. package/dist/test-runner/report.js +0 -198
  190. package/dist/test-runner/report.js.map +0 -1
  191. package/dist/test-runner/rpc.d.ts +0 -56
  192. package/dist/test-runner/rpc.d.ts.map +0 -1
  193. package/dist/test-runner/rpc.js +0 -98
  194. package/dist/test-runner/rpc.js.map +0 -1
  195. package/dist/test-runner/runtime.d.ts +0 -2
  196. package/dist/test-runner/runtime.js +0 -659
  197. package/dist/test-runner/runtime.js.map +0 -1
  198. package/dist/test-runner/task-graph.d.ts +0 -38
  199. package/dist/test-runner/task-graph.d.ts.map +0 -1
  200. package/dist/test-runner/task-graph.js +0 -182
  201. package/dist/test-runner/task-graph.js.map +0 -1
  202. package/dist/throttle-DKKzX1qC.js +0 -59
  203. package/dist/throttle-DKKzX1qC.js.map +0 -1
  204. package/dist/totp-95OAa20j.js +0 -64
  205. package/dist/totp-95OAa20j.js.map +0 -1
  206. package/dist/totp-BjtoQNfu.cjs +0 -64
  207. package/dist/totp-BjtoQNfu.cjs.map +0 -1
  208. package/dist/totp-CZLLKfOC.js +0 -200
  209. package/dist/totp-CZLLKfOC.js.map +0 -1
  210. package/dist/totp-DAxys-r0.js +0 -199
  211. package/dist/totp-DAxys-r0.js.map +0 -1
  212. package/dist/totp-DIbrZtI7.js +0 -189
  213. package/dist/totp-DIbrZtI7.js.map +0 -1
  214. package/dist/totp-Df252ZdA.cjs +0 -192
  215. package/dist/totp-Df252ZdA.cjs.map +0 -1
  216. package/dist/totp-DfekTBk3.js +0 -211
  217. package/dist/totp-DfekTBk3.js.map +0 -1
  218. package/dist/totp-Dwft0Kz7.js +0 -3
  219. package/dist/totp-WY6l0ysP.js +0 -190
  220. package/dist/totp-WY6l0ysP.js.map +0 -1
  221. package/dist/tunnel-BVSMXctM.cjs.map +0 -1
  222. package/dist/tunnel-D7xkimBu.js.map +0 -1
  223. /package/dist/{test-runner/bin.d.ts → stubs/bin-devtools-mcp.d.ts} +0 -0
package/README.md CHANGED
@@ -47,7 +47,7 @@ pnpm dev:phone # AIT_TUNNEL=1 pnpm dev 와 동일
47
47
  # 터미널에 QR 출력 → 폰 카메라로 스캔 → launcher PWA에서 자동 열림
48
48
  ```
49
49
 
50
- `tunnel: { cdp: true }`를 켜면 같은 QR 한 번으로 화면 미리보기 + on-device CDP가 함께 열려 실기기 WebKit의 DOM·콘솔·예외를 MCP로 관측합니다 (`call_sdk`는 환경 2에서 mock — 실 SDK는 환경 3).
50
+ `tunnel: { cdp: true }`를 켜면 같은 QR 한 번으로 화면 미리보기 + on-device CDP가 함께 열려 실기기 WebKit의 DOM·콘솔·예외를 MCP로 관측합니다 (`call_sdk`는 환경 2에서 mock — 실 SDK는 환경 3). CDP를 쓰려면 디버깅 패키지 두 개를 추가로 설치하세요 — 아래 [디버깅 패키지](#디버깅-패키지-환경-23) 참고.
51
51
 
52
52
  사전: 폰에 `https://devtools.aitc.dev/launcher/` 를 홈 화면에 한 번 추가. 상세: [`docs/scenarios/env-2.md`](./docs/scenarios/env-2.md)
53
53
 
@@ -55,10 +55,10 @@ pnpm dev:phone # AIT_TUNNEL=1 pnpm dev 와 동일
55
55
 
56
56
  **환경 3 — intoss-private** (토스 WebView, HMR X, debug 전용)
57
57
 
58
- 실기기 토스 앱 WebView에서 dog-food 번들을 로드하고 MCP relay로 디버깅합니다.
58
+ 실기기 토스 앱 WebView에서 dog-food 번들을 로드하고 MCP relay로 디버깅합니다. `@ait-co/debugger` 설치가 필요합니다 — 아래 [디버깅 패키지](#디버깅-패키지-환경-23) 참고.
59
59
 
60
60
  ```bash
61
- devtools-mcp # MCP 서버 시작 → QR 출력
61
+ npx -y -p @ait-co/debugger debugger # MCP 서버 시작 → QR 출력 (devDep이면 pnpm exec debugger)
62
62
  # ait build && ait deploy --scheme-only
63
63
  # start_attach(scheme_url) 호출 한 번으로 QR 생성 + 폰 attach까지 — QR 스캔하면 토스 앱 로드 + relay attach
64
64
  ```
@@ -73,7 +73,7 @@ HMR 없음(토스 WebView cold-load만). 상세: [`docs/scenarios/env-3.md`](./d
73
73
 
74
74
  ```ts
75
75
  // main.tsx (또는 미니앱 entry 최상단)
76
- import '@ait-co/devtools/in-app/auto';
76
+ import '@ait-co/debug-console/auto';
77
77
  ```
78
78
 
79
79
  이 한 줄이 하는 일:
@@ -85,7 +85,9 @@ import '@ait-co/devtools/in-app/auto';
85
85
 
86
86
  환경 3(intoss-private relay) 빌드는 relay QR deep-link가 `?debug=1&relay=<wss>` 파라미터를 실어 보내므로, 이 한 줄만 있으면 별도 게이트 코드가 필요 없습니다. 환경 2(PWA, `tunnel: { cdp: true }`)도 동일하게 동작합니다.
87
87
 
88
- > TOTP 인증이 필요한 dog-food 빌드는 빌드 define으로 `__DEBUG_TOTP_SECRET__`을 주입하고 `@ait-co/devtools/in-app`을 직접 import해 `evaluateDebugGate({ verifyTotpCode })` + `maybeAttach()`를 사용하세요. `in-app/auto`는 TOTP verifier주입하지 않으므로 C3 레이어가 비활성화됩니다.
88
+ 경로 `@ait-co/devtools/in-app/auto`는 0.2.x에서도 계속 resolve되지만 inert한 no-op 스텁이며 1.0.0에서 제거됩니다 import 경로로 옮기세요.
89
+
90
+ > TOTP 인증이 필요한 dog-food 빌드는 빌드 define으로 `__DEBUG_TOTP_SECRET__`을 주입하고 `@ait-co/debug-console`을 직접 import해 `evaluateDebugGate({ verifyTotpCode })` + `maybeAttach()`를 사용하세요. `in-app/auto`는 TOTP verifier를 주입하지 않으므로 C3 레이어가 비활성화됩니다.
89
91
 
90
92
  ## 자주 겪는 문제 5가지
91
93
 
@@ -99,7 +101,7 @@ relay에 붙은 페이지가 없는 상태입니다. `start_attach` → QR 스
99
101
 
100
102
  **"tunnel down" — 터널 응답 없음 또는 timeout**
101
103
 
102
- cloudflared quick tunnel은 수 시간 후 drop될 수 있습니다. `devtools-mcp` 프로세스를 재시작하면 새 tunnel URL이 발급됩니다. 재발급 후 QR을 다시 스캔하세요. (관련: [#290](https://github.com/apps-in-toss-community/devtools/issues/290))
104
+ cloudflared quick tunnel은 수 시간 후 drop될 수 있습니다. `debugger` 프로세스를 재시작하면 새 tunnel URL이 발급됩니다. 재발급 후 QR을 다시 스캔하세요. (관련: [#290](https://github.com/apps-in-toss-community/devtools/issues/290))
103
105
 
104
106
  **"page crash" — list_pages에 crashDetectedAt이 찍힘**
105
107
 
@@ -107,7 +109,7 @@ cloudflared quick tunnel은 수 시간 후 drop될 수 있습니다. `devtools-m
107
109
 
108
110
  **"SDK 부재" — window.__sdkCall 미주입**
109
111
 
110
- `call_sdk` 호출 시 `ok: false, error: "window.__sdkCall is not available"` 에러가 뜨면 SDK 브리지가 아직 설치되지 않은 상태입니다. 아래 "on-device 디버깅 한 줄 설정" 섹션을 참고해 `import '@ait-co/devtools/in-app/auto'`가 미니앱 entry에 추가돼 있는지 확인하세요. 환경 2(PWA)에서는 이 에러가 예상 결과입니다. (관련: [#285](https://github.com/apps-in-toss-community/devtools/issues/285))
112
+ `call_sdk` 호출 시 `ok: false, error: "window.__sdkCall is not available"` 에러가 뜨면 SDK 브리지가 아직 설치되지 않은 상태입니다. 아래 "on-device 디버깅 한 줄 설정" 섹션을 참고해 `import '@ait-co/debug-console/auto'`가 미니앱 entry에 추가돼 있는지 확인하세요. 환경 2(PWA)에서는 이 에러가 예상 결과입니다. (관련: [#285](https://github.com/apps-in-toss-community/devtools/issues/285))
111
113
 
112
114
  **"QR 스캔했는데 인증 실패" — TOTP 만료**
113
115
 
@@ -138,6 +140,26 @@ devtools는 같은 코드에서 두 개의 npm dist-tag를 동시에 운영합
138
140
 
139
141
  3.0이 정식(GA) 출시되면 stable `latest` peer가 3.0 라인으로 올라가고 beta 채널은 정리됩니다. devtools가 아직 mock하지 않은 API를 호출하면 런타임에 에러가 발생합니다 — 누락된 API는 [이슈](https://github.com/apps-in-toss-community/devtools/issues)로 알려주세요.
140
142
 
143
+ ### 디버깅 패키지 (환경 2·3)
144
+
145
+ **환경 1(로컬 브라우저 + mock + 패널)만 쓴다면 위 설치가 전부입니다.** 아무것도 더 설치하지 않아도 됩니다.
146
+
147
+ on-device CDP 디버깅(환경 2의 `tunnel: { cdp: true }`, 환경 3의 relay attach)을 쓰려면 디버깅 패키지 두 개를 추가로 설치하세요:
148
+
149
+ ```bash
150
+ pnpm add -D @ait-co/debugger @ait-co/debug-console
151
+ ```
152
+
153
+ | 패키지 | 역할 | 번들 반입 |
154
+ |---|---|---|
155
+ | [`@ait-co/debugger`](https://www.npmjs.com/package/@ait-co/debugger) | MCP 데몬 · 실기기 테스트 러너 · dev-bridge(환경 2 CDP relay + QR 대시보드) | 안 됨 — devDependency / `npx` 전용 |
156
+ | [`@ait-co/debug-console`](https://www.npmjs.com/package/@ait-co/debug-console) | on-device attach + 인앱 eruda 콘솔 | 됨 — debug 빌드에만 들어가는 유일한 패키지 |
157
+
158
+ 두 패키지 모두 devtools의 **optional peer**입니다.
159
+
160
+ - `@ait-co/debugger`가 없으면 `tunnel: { cdp: true }`는 CDP 배선을 건너뛰고 일반 화면 미리보기 터널로 degrade하며, 터미널에 설치 안내를 한 번 출력합니다.
161
+ - `@ait-co/debug-console`이 없으면 unplugin이 in-app attach를 아예 주입하지 않습니다 — attach 코드가 번들에 구조적으로 들어갈 수 없다는 뜻이고, 이게 디버그 표면의 기술적 경계입니다.
162
+
141
163
  ## Reference consumer
142
164
 
143
165
  [`sdk-example`](https://github.com/apps-in-toss-community/sdk-example)이 devtools의 reference consumer다. 모든 SDK API를 인터랙티브하게 실행해볼 수 있는 카탈로그 앱으로, 웹 데모는 <https://sdk-example.aitc.dev/>에서 바로 확인할 수 있다. 새 mock을 추가하면 sdk-example의 카드에서 그대로 동작하는 게 1차 sanity check. 단, 이 repo의 E2E suite는 sdk-example을 clone하지 않고 **내부 자기완결 fixture(`e2e/fixture/`)** 로 운영한다 — sdk-example이 깨져도 devtools CI는 영향받지 않는다.
@@ -280,7 +302,7 @@ aitDevtools.vite({ tunnel: { cdp: true } }); // 실기기 미리보기 + on-devi
280
302
 
281
303
  ## Production 빌드
282
304
 
283
- 기본적으로 devtools 플러그인은 **production 빌드에서 자동 비활성화**됩니다 (`NODE_ENV === 'production'`이면 alias 변환과 Panel 주입이 모두 스킵). 별도의 조건부 설정 없이도 안전합니다.
305
+ 기본적으로 devtools 플러그인은 **production 빌드에서 자동 비활성화**됩니다 (`NODE_ENV === 'production'`이면 alias 변환과 Panel 주입이 모두 스킵). 별도의 조건부 설정 없이도 안전합니다. `@ait-co/devtools`는 devDependency이고 production 번들에 기여하는 바이트 수는 0입니다. CI가 실제 소비자 fixture를 빌드해 결과물을 grep하는 방식으로 이를 강제합니다.
284
306
 
285
307
  스테이징 환경 등에서 production 빌드에서도 devtools를 사용하려면 `forceEnable` 옵션을 사용하세요:
286
308
 
@@ -391,9 +413,9 @@ launcher는 **PWA(홈 화면 앱)로 실행할 때만 동작**합니다. 일반
391
413
  >
392
414
  > `tunnel` 옵션은 Vite dev 모드에서만 동작합니다 — production 빌드는 `forceEnable`이어도 터널을 띄우지 않습니다. 다른 번들러(Webpack/Rspack 등)에서는 무시됩니다. 이 옵션을 켜면 `cloudflared` / `qrcode-terminal`가 동적 import로만 로드되므로, 끄면 번들 그래프에 들어오지 않습니다.
393
415
 
394
- ### 한 줄 셋업 (예정)
416
+ ### 한 줄 셋업
395
417
 
396
- 위 "프로젝트당 1회" 단계(vite.config 패치 + `onlyBuiltDependencies` + `dev:phone` 스크립트)는 향후 [`agent-plugin`](https://github.com/apps-in-toss-community/agent-plugin) `/ait setup phone` 같은 단일 명령으로 흡수할 예정입니다 (명령 이름은 잠정). 이 README가 그 자동화의 명세서 역할을 하므로, 수동 셋업 단계가 줄어들어도 동작 모델 자체는 동일합니다.
418
+ 위 "프로젝트당 1회" 단계(vite.config 패치 + `onlyBuiltDependencies` + `dev:phone` 스크립트)는 [`agent-plugin`](https://github.com/apps-in-toss-community/agent-plugin) `/ait:setup-phone-preview` 명령으로 자동화돼 있습니다. 이 README가 그 자동화의 명세서 역할을 하므로, 수동 셋업 단계가 줄어들어도 동작 모델 자체는 동일합니다.
397
419
 
398
420
  ## Device API 모드 시스템
399
421
 
@@ -632,6 +654,7 @@ __ait.update({ networkStatus: 'OFFLINE' });
632
654
  __ait.patch('permissions', { camera: 'denied' });
633
655
  __ait.patch('deviceModes', { location: 'web' });
634
656
  __ait.patch('iap', { nextResult: 'USER_CANCELED' });
657
+ __ait.patch('failureModes', { loadAdMob: 'PLACEMENT_ID_FETCH_FAILED' }); // 실기기 광고 지면 조회 실패 재현
635
658
 
636
659
  // 이벤트 트리거
637
660
  __ait.trigger('backEvent');
@@ -746,6 +769,8 @@ unsubscribe(); // 구독 해제
746
769
  | `TossAds.destroy/destroyAll` | no-op |
747
770
  | `loadFullScreenAd` / `showFullScreenAd` | GoogleAdMob과 유사한 흐름 |
748
771
 
772
+ > 실패 다이얼(`failureModes.loadAdMob`, 패널 `forceNoFill`)을 설정하지 않으면 위 이벤트들은 매번 동일하게 발화합니다 — mock은 `adGroupId`를 판정에 쓰지 않고, 서버 측 지면(placement) 조회 단계를 모델링하지 않습니다. 실기기는 광고가 존재하기도 전에 지면 조회 자체가 실패해(예: `PLACEMENT_ID_FETCH_FAILED`) 즉시 거부될 수 있으므로, mock의 `loaded` 발화가 "실기기에서 광고가 실제로 나간다"는 신호는 아닙니다. 로컬에서 이 실패를 재현하려면: `__ait.patch('failureModes', { loadAdMob: 'PLACEMENT_ID_FETCH_FAILED' })`.
773
+
749
774
  ### 이벤트
750
775
 
751
776
  | API | Mock 동작 |
@@ -853,6 +878,19 @@ it('Storage에 값을 저장하고 읽을 수 있다', async () => {
853
878
  });
854
879
  ```
855
880
 
881
+ ## 실기기 테스트 러너 (`debugger-test`)
882
+
883
+ 위 "테스트에서의 활용"이 데스크톱 jsdom에서 mock을 검증하는 경로라면, 같은 스타일의 테스트를 **실기기 토스 앱 WebView(환경 3)에서 실 SDK로** 돌리는 러너는 `@ait-co/debugger`로 이동했습니다(#818) — bin도 `devtools-test`에서 `debugger-test`로 바뀌었습니다.
884
+
885
+ ```bash
886
+ pnpm add -D @ait-co/debugger
887
+ pnpm exec debugger-test 'src/**/*.ait.test.ts' \
888
+ --scheme-url "intoss-private://my-mini-app?_deploymentId=<uuid>" \
889
+ --cell-sdk-line 3.x --cell-platform ios --report-dir .ait-report
890
+ ```
891
+
892
+ 전체 플래그·QR 스캔 절차·산출물 레퍼런스는 이제 `@ait-co/debugger` 패키지가 정본입니다 — `debugger-test --help`를 참고하세요. 미니앱 entry에 필요한 한 줄만 이 패키지 쪽에 남아 있습니다: `import '@ait-co/debug-console/auto'` ([위 섹션](#on-device-디버깅-한-줄-설정)).
893
+
856
894
  ## SDK 업데이트 대응
857
895
 
858
896
  devtools는 [`@apps-in-toss/web-framework`](https://www.npmjs.com/package/@apps-in-toss/web-framework)를 추적하고, [`sdk-example`](https://github.com/apps-in-toss-community/sdk-example)은 원본 SDK와 devtools를 모두 추적한다. 즉 새 SDK 버전이 나오면 (1) devtools가 mock/타입 시그니처를 따라잡고 → (2) sdk-example이 양쪽 새 버전을 동시에 반영하는 흐름. devtools 단독 PR이 sdk-example을 깨뜨리면 양쪽을 함께 본다.
@@ -965,207 +1003,42 @@ Turbopack은 unplugin을 지원하지 않으므로, `next.config.js`에서 `reso
965
1003
  import '@ait-co/devtools/panel';
966
1004
  ```
967
1005
 
968
- ### `devtools-mcp` — 이미 실행 중인 세션이 있을 때
969
-
970
- 두 번째 `devtools-mcp` 실행 시 "기존 debug-mode 세션이 이미 실행 중" 메시지가 stderr에 출력됩니다. 기존 PID와 wssUrl이 함께 표시됩니다.
971
-
972
- 회복 방법:
973
-
974
- ```bash
975
- # 기존 세션을 직접 종료
976
- kill <PID>
977
-
978
- # 또는 --force 플래그로 기존 세션을 종료하고 takeover
979
- npx @ait-co/devtools devtools-mcp --force
980
- # local 모드라면:
981
- npx @ait-co/devtools devtools-mcp --target=local --force
982
- ```
983
-
984
- `--takeover`도 `--force`의 alias로 동일하게 동작합니다.
985
-
986
1006
  ## MCP Server
987
1007
 
988
- AI 코딩 에이전트(Claude Code, Cursor ) [MCP(Model Context Protocol)](https://modelcontextprotocol.io/)
989
- 통해 실행 중인 미니앱을 직접 관측할 수 있습니다. 단일 `devtools-mcp` bin이 두 모드를 제공합니다.
990
-
991
- 로컬 브라우저(환경 1)와 폰 토스 앱 WebView(환경 2·3)는 둘 다 CDP를 말하므로 모든 tool이 두 환경에서 동일하게 동작합니다 — 갈라지는 건 attach 전략(`--target=relay` vs `--target=local`)뿐입니다.
992
-
993
- | 모드 + 타깃 | 호출 | 환경 변수 | 대상 | tool |
994
- |---|---|---|---|---|
995
- | `--target=mobile` (env 2) | `devtools-mcp` → `start_debug({mode:'relay-sandbox'})` | `AIT_RELAY_BASE_URL`, `AIT_TUNNEL_BASE_URL` | 실기기 Safari/WebKit PWA (외부 Chii relay + cloudflared 터널, 환경 2) | console/network/page + DOM/snapshot/screenshot |
996
- | `--mode=debug --target=relay` (기본값, env 3) | `devtools-mcp` → `start_debug({mode: 'relay-staging'})` | — | 폰 안 dog-food 번들 (CDP/Chii relay + cloudflared 터널, 환경 3) | 동일 + `AIT.*` |
997
- | `--mode=debug --target=local` (env 1) | `devtools-mcp --target=local` | `MCP_ENV=mock` (자동) | MCP가 직접 기동한 로컬 Chromium (CDP direct-attach, relay 불필요, 환경 1) | 동일 |
998
- | `--mode=dev` | `devtools-mcp --mode=dev` | `MCP_ENV=mock` (자동) | 실행 중인 Vite dev server의 mock state (AIT.* 전용, CDP 없음) | `AIT.*` (+ `devtools_get_mock_state` alias) |
999
-
1000
- `--target=local`은 `AIT_DEVTOOLS_URL`(기본 `http://localhost:5173`)을 열고 로컬 Chromium에 CDP direct-attach합니다 — relay나 터널이 필요하지 않습니다. `--mode=dev`는 Vite dev server의 mock-state HTTP endpoint를 읽으며 CDP tool은 제공하지 않습니다. 세션 내 환경 전환은 `start_debug(mode)` 한 번으로 처리됩니다: `relay-sandbox`(env 2 PWA), `relay-staging`(env 3 dogfood), `local-browser`(env 1).
1001
-
1002
- #### 환경 2 (실기기 PWA CDP) — `--target=mobile`
1003
-
1004
- 토스 검수 없이 실기기 WebKit 엔진에서 CDP 디버깅이 가능한 모드입니다. [`tunnel:{cdp:true}`](#tunnel-옵션)를 켠 Vite dev server가 앱 HTTP 터널과 Chii relay 터널을 두 개 띄우고, MCP는 그 relay에 붙어 `start_attach` → launcher QR을 제공합니다.
1005
-
1006
- **진입 절차:**
1007
-
1008
- 1. Vite dev server를 CDP 터널 모드로 기동:
1009
- ```bash
1010
- AIT_TUNNEL_CDP=1 pnpm exec vite --config e2e/fixture/vite.config.ts
1011
- ```
1012
- 터미널 배너에 두 URL이 출력됩니다:
1013
- - **앱 HTTP 터널** `https://<A>.trycloudflare.com` → `AIT_TUNNEL_BASE_URL`로 설정
1014
- - **relay wss 터널** `wss://<B>.trycloudflare.com` → `AIT_RELAY_BASE_URL`의 `https://` 형으로 설정
1015
-
1016
- 2. MCP server를 mobile 모드로 기동 (별도 터미널):
1017
- ```json
1018
- {
1019
- "mcpServers": {
1020
- "ait-debug": {
1021
- "command": "npx",
1022
- "args": ["-y", "@ait-co/devtools", "devtools-mcp"],
1023
- "env": {
1024
- "AIT_RELAY_BASE_URL": "https://<B>.trycloudflare.com",
1025
- "AIT_TUNNEL_BASE_URL": "https://<A>.trycloudflare.com"
1026
- }
1027
- }
1028
- }
1029
- }
1030
- ```
1031
-
1032
- 3. Claude Code 세션에서 진입:
1033
- ```
1034
- start_debug({mode: 'relay-sandbox'})
1035
- start_attach()
1036
- ```
1037
- QR을 폰 카메라로 스캔하면 launcher PWA가 앱을 프레임에 열고 Chii target.js를 주입합니다.
1038
-
1039
- 4. `list_pages()` → 페이지 1개 확인. `take_screenshot()` 등 CDP tool을 사용합니다.
1040
-
1041
- **env 2의 fidelity 경계**: SDK mock을 씁니다 (실 SDK 호출 불가) — `call_sdk`는 환경 2에서 mock을 칩니다. 실 SDK fidelity가 필요하면 환경 3으로 올라가세요. CDP는 실 WebKit 엔진 위에서 동작하므로 DOM·console·screenshot은 실기기 화면을 그대로 반영합니다.
1042
-
1043
- **로컬 PC 검증**: `e2e/launcher-cdp.test.ts`가 node-side relay 기동(`startChiiRelay({port:0})`)과 launcher 파라미터 포워딩(Playwright)을 자동 검증합니다. browser-side Chii target.js 주입은 localhost 호스트 게이트(Layer B1)와 ws:// vs wss:// 제약으로 CI에서 검증 불가 — 위 수동 절차(실기기 trycloudflare.com 호스트)에서 완성됩니다.
1044
-
1045
- ### Debug 모드 (CDP via Chii)
1046
-
1047
- 실기기 relay 디버깅 루프(dog-food 빌드 → QR 스캔 → relay attach)의 단계별 절차와 복구 방법은 **[`docs/dogfood-relay-loop.md`](./docs/dogfood-relay-loop.md)** 를 참고하세요. crash가 발생한 경우 — `list_pages.crashDetectedAt`, iOS Console.app `.ips` 분석, redact 절차를 포함한 원인 추적 절차는 **[`docs/crash-triage.md`](./docs/crash-triage.md)** 를 참고하세요.
1048
-
1049
- read-only tool만 노출합니다. 도구는 attach 상태에 따라 2단계로 등록됩니다 — attach 전에는 bootstrap
1050
- 도구(`start_attach`·`list_pages`)만 보이고, 릴레이/로컬 페이지가 attach되면 `notifications/tools/list_changed`로
1051
- attach 의존 도구가 같은 세션에서 동적 등록됩니다(세션 재시작 불필요). 폰 attach 라운드트립은 fully wired
1052
- 상태이며 남은 것은 실기기 acceptance 한 번뿐입니다. tool 계층은 주입 가능한 CDP 연결 / AIT 소스를 mock해
1053
- CI에서 검증됩니다.
1054
-
1055
- `devtools-mcp`를 stdio로 실행하면 로컬 Chii 릴레이를 OS가 할당한 포트에 띄우고 cloudflared quick
1056
- tunnel로 공개 `wss://*.trycloudflare.com` URL을 발급한 뒤 QR을 터미널에 출력합니다(시크릿/인증
1057
- 코드는 출력하지 않습니다). 폰이 dog-food 진입 시 in-app attach UI가 그 URL로 릴레이에 붙으면,
1058
- 에이전트가 `chrome-devtools-mcp` 호환 tool로 console/network/page 상태를 read합니다. 사람이 폰을
1059
- 지켜볼 필요 없이 회귀를 단독 진단하는 것이 목표입니다.
1060
-
1061
- 환경 3 (intoss-private relay) — `devtools-mcp`를 그대로 기동한 뒤 `start_debug(mode)`로 진입합니다:
1008
+ MCP 표면(데몬 · attach · CDP tool) `@ait-co/debugger`로 이동했습니다(#818). 에이전트 등록도 이제 devtools가 아니라 debugger 가리킵니다:
1062
1009
 
1063
1010
  ```json
1064
1011
  {
1065
1012
  "mcpServers": {
1066
1013
  "ait-debug": {
1067
- "command": "pnpm",
1068
- "args": ["exec", "devtools-mcp"]
1014
+ "command": "npx",
1015
+ "args": ["-y", "-p", "@ait-co/debugger", "debugger"]
1069
1016
  }
1070
1017
  }
1071
1018
  }
1072
1019
  ```
1073
1020
 
1074
- - 환경 3 (dog-food relay): `start_debug({mode: 'relay-staging'})`
1075
- **세션 내 환경 전환은 `start_debug(mode)`가 단일 진입 경로**입니다.
1076
-
1077
- | Tool | CDP / AIT 백킹 | 설명 |
1078
- |---|---|---|
1079
- | `list_console_messages` | `Runtime.consoleAPICalled` | 최근 console.log/warn/error 메시지 (level, text, timestamp, args) |
1080
- | `list_network_requests` | `Network.requestWillBeSent` + `responseReceived` | 최근 XHR/fetch 요청 (url, method, status, timing) |
1081
- | `list_pages` | Chii 릴레이 target 목록 | attach된 페이지 + tunnel 상태 + wss URL |
1082
- | `start_attach` | (순수 합성 + attach 대기) | `ait deploy --scheme-only` URL에 `debug=1`+릴레이 URL을 끼워 self-attach deep-link를 합성하고 QR을 출력한 뒤, 폰이 attach될 때까지 같은 호출 안에서 대기한다(QR 생성·attach가 한 호출). `mode`로 세션 환경을 함께 전환할 수 있고, 대기 중 TOTP 코드를 자동 재발행한다. 환경 2·3 진입 도구(bootstrap) — `list_pages` 선행 불필요 |
1083
- | `get_dom_document` | `DOM.getDocument` | DOM 트리 read (구조/레이아웃 회귀 진단) |
1084
- | `take_snapshot` | `DOMSnapshot.captureSnapshot` | 페이지 스냅샷 (documents + interned strings, 시각 회귀 진단) |
1085
- | `take_screenshot` | `Page.captureScreenshot` | 페이지 PNG 스크린샷 (MCP image content block 반환) |
1086
- | `measure_safe_area` | `Runtime.evaluate` | attach된 페이지에서 safe-area 프로브 실행 → 정규화된 safe-area inset·뷰포트 geometry·DPR·User-Agent 반환. read-only. relay 세션(폰 attach)에서 viewport preset을 extrapolated/placeholder→measured로 승급할 ground truth 수집용. attach 필요 (`list_pages` 먼저) |
1087
- | `evaluate` | `Runtime.evaluate` | attach된 페이지에서 임의 JS 표현식 평가(returnByValue) → 결과 반환. **read-only 아님** — 표현식이 부작용(DOM 변경·SDK 호출·상태 변경)을 일으킬 수 있음. attach 필요 |
1088
- | `call_sdk` | `window.__sdkCall` 브리지 (`Runtime.evaluate` 경유) | dog-food SDK 메서드를 `window.__sdkCall` 브리지로 호출 (`@apps-in-toss/web-framework`가 `__DEBUG_BUILD__` 번들에서만 export). **read-only 아님** — SDK 호출은 부작용(내비게이션·결제·권한 등). 환경 3(실기기 relay)에선 실 SDK, 환경 1(로컬 mock)에선 mock SDK. 환경 2(PWA)는 SDK 미주입으로 사용 불가. attach 필요. `{ok,value}` / `{ok,error}` 반환 |
1089
- | `AIT.getSdkCallHistory` | AIT 도메인 | SDK 호출 trace (method, args, result/error, timestamp) |
1090
- | `AIT.getMockState` | AIT 도메인 | mock state 스냅샷 (`window.__ait`) |
1091
- | `AIT.getOperationalEnvironment` | AIT 도메인 | `getOperationalEnvironment()` + SDK 버전 |
1092
-
1093
- `AIT.*`는 raw CDP가 못 잡는 영역으로, 같은 MCP server가 CDP와 함께 forward합니다. debug 모드에서는
1094
- in-app 측이 Chii 채널로 응답합니다.
1095
-
1096
- ### Dev 모드 (mock state)
1097
-
1098
- `devtools-mcp --mode=dev`는 실행 중인 브라우저의 mock state를 읽습니다. debug 모드와 같은 `AIT.*`
1099
- tool surface를 공유합니다.
1100
-
1101
- #### 구조
1102
-
1103
- ```
1104
- 브라우저 (aitState)
1105
- └─ POST /api/ait-devtools/state (panel이 state 변경 시 자동 push)
1106
- └─ Vite dev server (unplugin mcp: true 로 등록)
1107
- └─ GET /api/ait-devtools/state
1108
- └─ MCP stdio server (dist/mcp/server.js)
1109
- └─ AI 에이전트 (AIT.getMockState tool)
1110
- ```
1111
-
1112
- #### 설정
1113
-
1114
- **1. Vite 플러그인에 `mcp: true` 추가**
1115
-
1116
- ```ts
1117
- // vite.config.ts
1118
- import aitDevtools from '@ait-co/devtools/unplugin';
1119
-
1120
- export default {
1121
- plugins: [aitDevtools.vite({ mcp: true })],
1122
- };
1123
- ```
1124
-
1125
- **2. MCP 클라이언트 설정 (예: Claude Code `.claude/settings.json`)**
1126
-
1127
- ```json
1128
- {
1129
- "mcpServers": {
1130
- "ait-devtools": {
1131
- "command": "pnpm",
1132
- "args": ["exec", "devtools-mcp", "--mode=dev"],
1133
- "env": {
1134
- "AIT_DEVTOOLS_URL": "http://localhost:5173"
1135
- }
1136
- }
1137
- }
1138
- }
1139
- ```
1140
-
1141
- `AIT_DEVTOOLS_URL`은 기본값이 `http://localhost:5173`이므로 기본 포트를 쓰면 생략 가능합니다.
1142
-
1143
- **3. 앱을 브라우저에서 열고, AI 에이전트에서 tool 호출**
1144
-
1145
- ```
1146
- > AIT.getMockState
1147
- ```
1148
-
1149
- 현재 mock state 전체(권한, 위치, 인증, 네트워크, IAP 등)를 JSON으로 반환합니다.
1150
-
1151
- | Tool | 설명 |
1152
- |---|---|
1153
- | `AIT.getMockState` | 현재 `AitDevtoolsState` 스냅샷 반환 (read-only) |
1154
- | `AIT.getOperationalEnvironment` | mock state의 `environment` + `appVersion` 기반 환경/버전 |
1155
- | `AIT.getSdkCallHistory` | dev 모드에서는 빈 목록 (HTTP endpoint가 trace를 기록하지 않음) |
1156
- | `devtools_get_mock_state` | `AIT.getMockState`의 하위호환 alias (신규 설정은 `AIT.getMockState` 권장) |
1021
+ 이 서버가 주는 것: 로컬 브라우저(환경 1)·PWA(환경 2)·intoss-private WebView(환경 3)에서 실행 중인 미니앱을 CDP로 관측 — console, network, DOM, snapshot, screenshot — 그리고 환경 2·3 on-device 진입용 `start_attach`. 전체 tool 목록·모드/타깃 매트릭스·환경별 설정은 [`@ait-co/debugger`](https://www.npmjs.com/package/@ait-co/debugger) 패키지 문서가 정본입니다.
1157
1022
 
1158
1023
  ## 패키지 Export 구조
1159
1024
 
1025
+ 이 패키지가 실제로 출하하는 진입점입니다:
1026
+
1160
1027
  | Import path | 용도 |
1161
1028
  |---|---|
1162
- | `@ait-co/devtools` 또는 `@ait-co/devtools/mock` | 모든 mock export (번들러 alias 대상) |
1029
+ | `@ait-co/devtools` (= `/mock`) | 번들러 alias 대상, 모든 mock export |
1163
1030
  | `@ait-co/devtools/panel` | Floating DevTools Panel (import 시 자동 마운트) |
1164
1031
  | `@ait-co/devtools/unplugin` | 번들러 플러그인 (.vite, .webpack, .rspack, .esbuild, .rollup) |
1165
- | `@ait-co/devtools/mcp/server` | dev-mode MCP stdio server 함수 (Node.js) |
1166
- | `@ait-co/devtools/mcp/cli` | `devtools-mcp` bin 진입점 (debug / dev 모드, Node.js) |
1167
- | `@ait-co/devtools/in-app` | In-app debug attach — 런타임 gate(layer B·C) + Chii target.js 주입. 소비자가 `if (__DEBUG_BUILD__)`로 import를 감싸 release 빌드에서 DCE — dog-food 빌드 전용 |
1168
- | `@ait-co/devtools/in-app/auto` | Self-gating side-effect entry — `import '@ait-co/devtools/in-app/auto'` 한 줄로 attach + SDK 브리지 설치. URL 파라미터(`?debug=1` / `?relay=`) 또는 DEV 빌드에서만 활성화, 일반 프로덕션 로드는 dormant. [위 섹션](#on-device-디버깅-한-줄-설정) 참고 |
1032
+
1033
+ 아래는 **전환 스텁**입니다 0.2.x에만 존재하고 1.0.0에서 제거됩니다(#818). 패키지로 마이그레이션하세요.
1034
+
1035
+ | Import path | 이동처 | import |
1036
+ |---|---|---|
1037
+ | `@ait-co/devtools/mcp/server` | `@ait-co/debugger/mcp/server` | throw |
1038
+ | `@ait-co/devtools/mcp/cli` | `@ait-co/debugger/mcp/cli` | throw |
1039
+ | `@ait-co/devtools/test-runner` | `@ait-co/debugger/test-runner` | throw |
1040
+ | `@ait-co/devtools/in-app` | `@ait-co/debug-console` | no-op + `console.error` 1회 |
1041
+ | `@ait-co/devtools/in-app/auto` | `@ait-co/debug-console/auto` | no-op + `console.error` 1회 |
1169
1042
 
1170
1043
  ## 라이센스
1171
1044
 
@@ -1,138 +1 @@
1
- //#region src/in-app/auto.d.ts
2
- /**
3
- * @ait-co/devtools/in-app/auto — self-gating side-effect entry.
4
- *
5
- * Consumers add a single line to their mini-app entry:
6
- *
7
- * import '@ait-co/devtools/in-app/auto';
8
- *
9
- * The entry self-gates: if none of the debug activation signals are present
10
- * (no `?debug=1`, no `?relay=`, and not a DEV build), it does nothing. The
11
- * imported chunk stays dormant and `window.__sdk` / `window.__sdkCall` are
12
- * never installed on a normal production load.
13
- *
14
- * DEPRECATED for builds that require debug code to be PHYSICALLY ABSENT from
15
- * the release bundle. This entry is a RUNTIME self-gate, not a build-time one:
16
- * the imported chunk (Chii target.js injection, the SDK bridge, and the eruda
17
- * console it pulls in via `maybeAttach()`) stays in the production bundle as a
18
- * dormant chunk and is only kept asleep at runtime. If your threat model needs
19
- * "zero bytes of debug surface in release" (no dormant chunk to extract or
20
- * re-enable), do NOT use this entry. Instead guard the call site yourself:
21
- *
22
- * if (__DEBUG_BUILD__) {
23
- * import('@ait-co/devtools/in-app').then((m) => m.maybeAttach());
24
- * }
25
- *
26
- * with `define: { __DEBUG_BUILD__: 'false' }` in your release build — the
27
- * bundler then dead-code-eliminates the whole `@ait-co/devtools/in-app` graph
28
- * (verified on Vite 8/rolldown). This entry stays for the convenience case
29
- * where a dormant chunk gated at runtime is acceptable.
30
- *
31
- * When the gate passes it:
32
- * 1. Calls `maybeAttach()` — runs the full Layer B/C gate (host allowlist,
33
- * opt-in params, relay URL, TOTP) and injects the Chii `target.js` script.
34
- * Gate semantics are NOT changed — this is a thin self-gate wrapper.
35
- * 2. Installs the SDK bridge (`window.__sdk` / `window.__sdkCall`) so an AI
36
- * agent can drive any SDK API over the CDP relay without hand-synthesising
37
- * the Granite/ReactNative bridge envelope. SDK access uses a dynamic
38
- * import of `@apps-in-toss/web-framework` — the peer is optional, so if
39
- * the SDK is not installed the bridge install is silently skipped
40
- * (fail-silent). The namespace mirror pattern (iterate `Object.keys`) is
41
- * SDK version-neutral: 2.x and 3.x are both covered without any static
42
- * import that would couple the entry to a specific SDK line.
43
- *
44
- * SECRET-HANDLING: no secret, TOTP code, relay URL, or host value is ever
45
- * logged or surfaced beyond the reason enum in `maybeAttach()`.
46
- *
47
- * Layer A (build-time DCE) is NOT enforced here — this entry IS the
48
- * consumer-facing alternative to `if (__DEBUG_BUILD__) { … }`. The self-gate
49
- * below performs the same dormancy guarantee via a URL param check, which is
50
- * safe in a side-effect import context (the gate runs at module evaluation
51
- * time, before any React tree mounts). Consumers who already manage their own
52
- * `__DEBUG_BUILD__` guard can keep using `@ait-co/devtools/in-app` directly.
53
- *
54
- * DEV detection uses two complementary signals:
55
- * 1. `import.meta.env.DEV` — resolved by the consumer's bundler at their
56
- * build time (Vite/Webpack/Rspack inject the value via top-level source
57
- * transforms). Works when the consumer's source code (not node_modules)
58
- * is processed — same pattern used by the polyfill's `auto` entry.
59
- * 2. `process.env.NODE_ENV === 'development'` — resolved by the consumer's
60
- * bundler via esbuild `define` (Vite dep-prebundle) or DefinePlugin
61
- * (webpack/Rspack). This token IS substituted in dep code inside
62
- * node_modules (how React's own dev/prod branching works), fixing the
63
- * env-1 regression where signal (1) was never injected into dep code
64
- * (sdk-example#180 / issue #520).
65
- * IMPORTANT: the `process.env.NODE_ENV` token must be written verbatim
66
- * — bundler define substitution is a textual token match. A `typeof
67
- * process` guard would survive substitution as-is and always evaluate to
68
- * `false` in a browser, killing the comparison. Instead we rely on
69
- * try/catch: if `process` is not defined (raw ESM in a browser without
70
- * bundler substitution) a ReferenceError is caught → fail-closed (dormant).
71
- */
72
- declare global {
73
- interface Window {
74
- /**
75
- * Entire `@apps-in-toss/web-framework` export namespace mirrored onto a
76
- * plain writable object. Installed by the auto entry when `?debug=1` /
77
- * `?relay=` is present in the URL, or in DEV builds.
78
- *
79
- * Lets an AI agent call any SDK API over a CDP relay without
80
- * hand-synthesising the Granite/ReactNative bridge envelope:
81
- * `window.__sdk.setDeviceOrientation({ type: 'landscape' })`
82
- */
83
- __sdk?: Record<string, unknown>;
84
- /**
85
- * Safe call wrapper for `window.__sdk`. Returns a JSON-serialisable
86
- * `{ ok: true, value }` or `{ ok: false, error }` tuple even for
87
- * throwing/async SDK functions — ideal for `Runtime.evaluate` results.
88
- *
89
- * @example
90
- * window.__sdkCall('setDeviceOrientation', { type: 'landscape' })
91
- */
92
- __sdkCall?: (name: string, ...args: unknown[]) => Promise<{
93
- ok: boolean;
94
- value?: unknown;
95
- error?: string;
96
- }>;
97
- }
98
- }
99
- /**
100
- * Detects whether the current build is a DEV build by consulting two signals.
101
- *
102
- * Signal A — `import.meta.env.DEV`:
103
- * Substituted by Vite/Webpack/Rspack in the consumer's own source files.
104
- * NOT substituted in node_modules dep code (esbuild prebundle does not
105
- * apply Vite's define pass to deps) — this was the root cause of #520.
106
- *
107
- * Signal B — `process.env.NODE_ENV === 'development'`:
108
- * Substituted by esbuild's dep-prebundle define pass (Vite) and by
109
- * DefinePlugin (webpack/Rspack) even inside node_modules. This is how
110
- * React itself gates its dev-only code paths. Writing the token verbatim
111
- * ensures textual substitution works; a `typeof process` guard would not
112
- * be substituted and would evaluate to `'undefined'` in the browser,
113
- * killing the comparison. A try/catch catches the ReferenceError when
114
- * `process` is genuinely absent (raw ESM without bundler, e.g. direct
115
- * browser import or test runners that leave identifiers in place) →
116
- * fail-closed (dormant).
117
- *
118
- * Exported for unit tests — pass an explicit `isDev` override to bypass
119
- * the environment detection in controlled test scenarios.
120
- */
121
- declare function detectDevSignal(): boolean;
122
- /**
123
- * Pure predicate for the self-gate. Exported for unit tests.
124
- *
125
- * @param isDev - Whether the consumer's bundler signals a DEV build.
126
- * Default: calls `detectDevSignal()` which consults both
127
- * `import.meta.env.DEV` (consumer source pass) and
128
- * `process.env.NODE_ENV === 'development'` (dep prebundle pass, fixing
129
- * the env-1 regression in issue #520).
130
- * Pass an explicit value in tests to control the DEV signal without
131
- * depending on the Vite/vitest build environment.
132
- * @param searchStr - URL search string to inspect. Defaults to
133
- * `window.location.search` when called in a browser context.
134
- */
135
- declare function shouldActivate(isDev?: boolean, searchStr?: string): boolean;
136
- //#endregion
137
- export { detectDevSignal, shouldActivate };
138
- //# sourceMappingURL=auto.d.ts.map
1
+ export { };