@things-factory/board-ai 10.1.24 → 10.1.26

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 (107) hide show
  1. package/PLAN-styling-tools.md +1 -1
  2. package/dist-client/server/service/assistant.d.ts +5 -4
  3. package/dist-client/server/service/assistant.js +35 -35
  4. package/dist-client/server/service/assistant.js.map +1 -1
  5. package/dist-client/server/service/styling/clear-tools.d.ts +2 -2
  6. package/dist-client/server/service/styling/clear-tools.js.map +1 -1
  7. package/dist-client/server/service/styling/copy-tools.d.ts +3 -3
  8. package/dist-client/server/service/styling/copy-tools.js +1 -1
  9. package/dist-client/server/service/styling/copy-tools.js.map +1 -1
  10. package/dist-client/server/service/styling/effect-tools.d.ts +2 -2
  11. package/dist-client/server/service/styling/effect-tools.js.map +1 -1
  12. package/dist-client/server/service/styling/fill-tools.d.ts +3 -3
  13. package/dist-client/server/service/styling/fill-tools.js +1 -1
  14. package/dist-client/server/service/styling/fill-tools.js.map +1 -1
  15. package/dist-client/server/service/styling/material-tools.d.ts +2 -2
  16. package/dist-client/server/service/styling/material-tools.js.map +1 -1
  17. package/dist-client/server/service/styling/registry.d.ts +6 -6
  18. package/dist-client/server/service/styling/registry.js +2 -2
  19. package/dist-client/server/service/styling/registry.js.map +1 -1
  20. package/dist-client/server/service/styling/stroke-tools.d.ts +2 -2
  21. package/dist-client/server/service/styling/stroke-tools.js.map +1 -1
  22. package/dist-client/server/service/styling/text-tools.d.ts +2 -2
  23. package/dist-client/server/service/styling/text-tools.js.map +1 -1
  24. package/dist-client/server/service/types.d.ts +6 -148
  25. package/dist-client/server/service/types.js.map +1 -1
  26. package/dist-client/server/service/validation/board-model-schema.d.ts +262 -262
  27. package/dist-client/server/service/validation/board-model-schema.js +4 -4
  28. package/dist-client/server/service/validation/board-model-schema.js.map +1 -1
  29. package/dist-client/server/service/validation/tool-validation.js +5 -5
  30. package/dist-client/server/service/validation/tool-validation.js.map +1 -1
  31. package/dist-client/tsconfig.tsbuildinfo +1 -1
  32. package/dist-server/index.d.ts +2 -2
  33. package/dist-server/index.js +2 -2
  34. package/dist-server/index.js.map +1 -1
  35. package/dist-server/service/assistant.d.ts +5 -4
  36. package/dist-server/service/assistant.js +37 -37
  37. package/dist-server/service/assistant.js.map +1 -1
  38. package/dist-server/service/board-ai-resolver.js +2 -2
  39. package/dist-server/service/board-ai-resolver.js.map +1 -1
  40. package/dist-server/service/index.d.ts +0 -1
  41. package/dist-server/service/index.js +0 -1
  42. package/dist-server/service/index.js.map +1 -1
  43. package/dist-server/service/patch-entry/board-patch-subscription.js +1 -1
  44. package/dist-server/service/patch-entry/board-patch-subscription.js.map +1 -1
  45. package/dist-server/service/patch-entry/patch-entry.d.ts +1 -1
  46. package/dist-server/service/patch-entry/patch-entry.js +1 -1
  47. package/dist-server/service/patch-entry/patch-entry.js.map +1 -1
  48. package/dist-server/service/styling/clear-tools.d.ts +2 -2
  49. package/dist-server/service/styling/clear-tools.js.map +1 -1
  50. package/dist-server/service/styling/copy-tools.d.ts +3 -3
  51. package/dist-server/service/styling/copy-tools.js +1 -1
  52. package/dist-server/service/styling/copy-tools.js.map +1 -1
  53. package/dist-server/service/styling/effect-tools.d.ts +2 -2
  54. package/dist-server/service/styling/effect-tools.js.map +1 -1
  55. package/dist-server/service/styling/fill-tools.d.ts +3 -3
  56. package/dist-server/service/styling/fill-tools.js +1 -1
  57. package/dist-server/service/styling/fill-tools.js.map +1 -1
  58. package/dist-server/service/styling/material-tools.d.ts +2 -2
  59. package/dist-server/service/styling/material-tools.js.map +1 -1
  60. package/dist-server/service/styling/registry.d.ts +6 -6
  61. package/dist-server/service/styling/registry.js +2 -2
  62. package/dist-server/service/styling/registry.js.map +1 -1
  63. package/dist-server/service/styling/stroke-tools.d.ts +2 -2
  64. package/dist-server/service/styling/stroke-tools.js.map +1 -1
  65. package/dist-server/service/styling/text-tools.d.ts +2 -2
  66. package/dist-server/service/styling/text-tools.js.map +1 -1
  67. package/dist-server/service/types.d.ts +6 -148
  68. package/dist-server/service/types.js.map +1 -1
  69. package/dist-server/service/validation/board-model-schema.d.ts +262 -262
  70. package/dist-server/service/validation/board-model-schema.js +4 -4
  71. package/dist-server/service/validation/board-model-schema.js.map +1 -1
  72. package/dist-server/service/validation/tool-validation.js +5 -5
  73. package/dist-server/service/validation/tool-validation.js.map +1 -1
  74. package/dist-server/tsconfig.tsbuildinfo +1 -1
  75. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +5 -0
  76. package/logs/connections-2026-09-17-16.log +0 -0
  77. package/package.json +8 -7
  78. package/server/index.ts +2 -2
  79. package/server/service/assistant-integration.test.ts +44 -44
  80. package/server/service/assistant-llm-smoke.test.ts +5 -5
  81. package/server/service/assistant.test.ts +86 -86
  82. package/server/service/assistant.ts +41 -43
  83. package/server/service/board-ai-resolver.ts +2 -2
  84. package/server/service/index.ts +0 -1
  85. package/server/service/patch-entry/board-patch-subscription.ts +1 -1
  86. package/server/service/patch-entry/patch-entry.ts +2 -2
  87. package/server/service/styling/clear-tools.ts +2 -2
  88. package/server/service/styling/copy-tools.ts +3 -3
  89. package/server/service/styling/effect-tools.ts +2 -2
  90. package/server/service/styling/fill-tools.test.ts +1 -1
  91. package/server/service/styling/fill-tools.ts +4 -4
  92. package/server/service/styling/material-tools.ts +2 -2
  93. package/server/service/styling/registry.ts +6 -6
  94. package/server/service/styling/stroke-tools.test.ts +1 -1
  95. package/server/service/styling/stroke-tools.ts +3 -3
  96. package/server/service/styling/text-tools.ts +2 -2
  97. package/server/service/tool-exposure.test.ts +7 -7
  98. package/server/service/types.ts +9 -110
  99. package/server/service/validation/board-model-schema.test.ts +3 -3
  100. package/server/service/validation/board-model-schema.ts +4 -4
  101. package/server/service/validation/tool-validation.ts +5 -5
  102. package/dist-server/service/apply-patch.d.ts +0 -47
  103. package/dist-server/service/apply-patch.js +0 -369
  104. package/dist-server/service/apply-patch.js.map +0 -1
  105. package/server/service/apply-patch-drift.test.ts +0 -831
  106. package/server/service/apply-patch.test.ts +0 -757
  107. package/server/service/apply-patch.ts +0 -411
@@ -9,6 +9,11 @@
9
9
  "date": 1789195002942,
10
10
  "name": "logs/connections-2026-09-12-15.log",
11
11
  "hash": "cf643fb0881a2a037b9657d9f0cab3f858825cbc597ef955ba6335a9305911c5"
12
+ },
13
+ {
14
+ "date": 1789629007157,
15
+ "name": "logs/connections-2026-09-17-16.log",
16
+ "hash": "c1197ab32a8e488c0eca99467d70519d581cbe046549df9f7106554417a0f184"
12
17
  }
13
18
  ],
14
19
  "hashType": "sha256"
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/board-ai",
3
- "version": "10.1.24",
3
+ "version": "10.1.26",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/client/index.js",
6
6
  "things-factory": true,
@@ -30,13 +30,14 @@
30
30
  "@apollo/client": "^3.13.0",
31
31
  "@operato/graphql": "^10.0.0",
32
32
  "@operato/i18n": "^10.0.0",
33
+ "@operato/scene-ops": "^10.14.1",
33
34
  "@operato/styles": "^10.0.0",
34
- "@things-factory/ai-assistant": "^10.1.24",
35
- "@things-factory/ai-client-base": "^10.1.20",
36
- "@things-factory/auth-base": "^10.1.24",
37
- "@things-factory/board-import": "^10.1.24",
35
+ "@things-factory/ai-assistant": "^10.1.26",
36
+ "@things-factory/ai-client-base": "^10.1.26",
37
+ "@things-factory/auth-base": "^10.1.26",
38
+ "@things-factory/board-import": "^10.1.26",
38
39
  "@things-factory/env": "^10.1.20",
39
- "@things-factory/shell": "^10.1.20",
40
+ "@things-factory/shell": "^10.1.26",
40
41
  "dompurify": "^3.0.0",
41
42
  "graphql-tag": "^2.12.6",
42
43
  "lit": "^3.1.2",
@@ -46,5 +47,5 @@
46
47
  "copyfiles": "^2.4.1",
47
48
  "rimraf": "^5.0.0"
48
49
  },
49
- "gitHead": "0d88a504e0ffa63cd91279b88c6998d4bf1b3d86"
50
+ "gitHead": "151bda14d899442c6846532ddded1e2bfe23a2f5"
50
51
  }
package/server/index.ts CHANGED
@@ -9,14 +9,14 @@
9
9
  * @example
10
10
  * ```ts
11
11
  * import { createAIClient } from '@things-factory/ai-client-base'
12
- * import { DefaultBoardAIAssistant, applyBoardEditPatch } from '@things-factory/board-ai'
12
+ * import { DefaultBoardAIAssistant, applyScenePatch } from '@things-factory/board-ai'
13
13
  *
14
14
  * const base = createAIClient({ provider: 'anthropic', apiKey: '...' })
15
15
  * const ai = new DefaultBoardAIAssistant(base, { scopes: ['fmsim'] })
16
16
  *
17
17
  * let board
18
18
  * const r = await ai.chat([{ role: 'user', content: 'AGV 3대를 우측에 추가' }], board)
19
- * if (r.patch) board = applyBoardEditPatch(board, r.patch)
19
+ * if (r.patch) board = applyScenePatch(board, r.patch)
20
20
  * console.log(r.reply)
21
21
  * ```
22
22
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 통합 테스트 — assistant.chat() → BoardEditPatch → apply-patch 풀 파이프라인.
2
+ * 통합 테스트 — assistant.chat() → SceneEditPatch → apply-patch 풀 파이프라인.
3
3
  *
4
4
  * 단위 테스트의 공백 보완:
5
5
  * - assistant.test.ts 는 patch 가 "올바르게 만들어지는지" 까지만 검증
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { AIClient } from '@things-factory/ai-client-base'
15
15
  import { DefaultBoardAIAssistant } from './assistant'
16
- import { applyBoardEditPatch, applyBoardEditPatchVerbose } from './apply-patch'
16
+ import { applyScenePatch, applyScenePatchVerbose } from '@operato/scene-ops'
17
17
  import type { BoardModel } from '@things-factory/board-import'
18
18
 
19
19
  // ── Mock provider — assistant.test.ts 의 패턴과 동일 ──────────────────
@@ -59,11 +59,11 @@ describe('통합 — addComponent 시나리오', () => {
59
59
  const r = await a.chat([{ role: 'user', content: 'rect 하나 추가' }], initial)
60
60
 
61
61
  expect(r.patch?.ops).toHaveLength(1)
62
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
62
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
63
63
  expect(verbose.applied).toHaveLength(1)
64
64
  expect(verbose.missed).toHaveLength(0)
65
- expect(verbose.board.components).toHaveLength(1)
66
- const added: any = verbose.board.components[0]
65
+ expect(verbose.model.components).toHaveLength(1)
66
+ const added: any = verbose.model.components[0]
67
67
  expect(added.type).toBe('rect')
68
68
  expect(added.left).toBe(50)
69
69
  expect(added.top).toBe(60)
@@ -84,9 +84,9 @@ describe('통합 — addComponent 시나리오', () => {
84
84
  const a = new DefaultBoardAIAssistant(client)
85
85
  const r = await a.chat([{ role: 'user', content: 'rect, circle, text 추가' }], initial)
86
86
 
87
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
88
- expect(verbose.board.components).toHaveLength(3)
89
- expect(verbose.board.components.map((c: any) => c.type)).toEqual(['rect', 'circle', 'text'])
87
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
88
+ expect(verbose.model.components).toHaveLength(3)
89
+ expect(verbose.model.components.map((c: any) => c.type)).toEqual(['rect', 'circle', 'text'])
90
90
  expect(verbose.applied).toHaveLength(3)
91
91
  expect(verbose.missed).toHaveLength(0)
92
92
  })
@@ -113,11 +113,11 @@ describe('통합 — modifyComponentByRefid 시나리오', () => {
113
113
  const a = new DefaultBoardAIAssistant(client)
114
114
  const r = await a.chat([{ role: 'user', content: '왼쪽 200으로' }], initial)
115
115
 
116
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
116
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
117
117
  expect(verbose.applied).toHaveLength(1)
118
118
  expect(verbose.missed).toHaveLength(0)
119
- const c1: any = verbose.board.components[0]
120
- const c2: any = verbose.board.components[1]
119
+ const c1: any = verbose.model.components[0]
120
+ const c2: any = verbose.model.components[1]
121
121
  expect(c1.left).toBe(200)
122
122
  expect(c1.top).toBe(20) // 다른 속성 보존
123
123
  expect(c1.width).toBe(100)
@@ -145,15 +145,15 @@ describe('통합 — modifyComponentByRefid 시나리오', () => {
145
145
  const a = new DefaultBoardAIAssistant(client)
146
146
  const r = await a.chat([{ role: 'user', content: '999 left=200' }], initial)
147
147
 
148
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
148
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
149
149
  expect(verbose.applied).toHaveLength(0)
150
150
  expect(verbose.missed).toHaveLength(1)
151
151
  // 보드는 그대로
152
- expect((verbose.board.components[0] as any).left).toBe(10)
152
+ expect((verbose.model.components[0] as any).left).toBe(10)
153
153
  })
154
154
  })
155
155
 
156
- describe('통합 — modifyBoard 시나리오 (root 속성)', () => {
156
+ describe('통합 — modifyScene 시나리오 (root 속성)', () => {
157
157
  test('"배경색 #0a1929" → root.fillStyle 만 변경, children 영향 없음', async () => {
158
158
  const initial = makeBoard([
159
159
  { refid: 1, type: 'rect', fillStyle: '#fff' }
@@ -164,7 +164,7 @@ describe('통합 — modifyBoard 시나리오 (root 속성)', () => {
164
164
  toolCalls: [
165
165
  {
166
166
  id: 'c1',
167
- name: 'modifyBoard',
167
+ name: 'modifyScene',
168
168
  arguments: { patch: { fillStyle: '#0a1929' } }
169
169
  }
170
170
  ]
@@ -174,15 +174,15 @@ describe('통합 — modifyBoard 시나리오 (root 속성)', () => {
174
174
  const a = new DefaultBoardAIAssistant(client)
175
175
  const r = await a.chat([{ role: 'user', content: '심해 컬러' }], initial)
176
176
 
177
- const after: any = applyBoardEditPatch(initial, r.patch!)
177
+ const after: any = applyScenePatch(initial, r.patch!)
178
178
  expect(after.fillStyle).toBe('#0a1929')
179
179
  expect(after.components).toHaveLength(1)
180
180
  expect((after.components[0] as any).fillStyle).toBe('#fff') // 자식은 그대로
181
181
  })
182
182
 
183
- test('"심해 분위기" multi-turn — getAtmosphereGuide 후 modifyBoard 패치가 root 에 반영', async () => {
183
+ test('"심해 분위기" multi-turn — getAtmosphereGuide 후 modifyScene 패치가 root 에 반영', async () => {
184
184
  // 실제 사용 패턴: AI 가 atmosphere primer 를 먼저 read tool 로 가져와 archetype
185
- // 보고, 거기서 추출한 patch (sky/exposure/dirLight 등) 로 modifyBoard 호출.
185
+ // 보고, 거기서 추출한 patch (sky/exposure/dirLight 등) 로 modifyScene 호출.
186
186
  const initial = makeBoard()
187
187
  const { client, callLog } = makeMockClient([
188
188
  // turn 1: read tool — guide 조회
@@ -194,7 +194,7 @@ describe('통합 — modifyBoard 시나리오 (root 속성)', () => {
194
194
  toolCalls: [
195
195
  {
196
196
  id: 'c2',
197
- name: 'modifyBoard',
197
+ name: 'modifyScene',
198
198
  arguments: {
199
199
  patch: { sky: 'color', skyColor: '#0a1929', exposure: 0.7, hemiIntensity: 1.5 }
200
200
  }
@@ -207,8 +207,8 @@ describe('통합 — modifyBoard 시나리오 (root 속성)', () => {
207
207
  const r = await a.chat([{ role: 'user', content: '심해 분위기로' }], initial)
208
208
 
209
209
  expect(callLog).toHaveLength(3) // read → write → finalize
210
- expect(r.patch?.ops).toHaveLength(1) // read 는 patch 에 안 잡히고 modifyBoard 만
211
- const after: any = applyBoardEditPatch(initial, r.patch!)
210
+ expect(r.patch?.ops).toHaveLength(1) // read 는 patch 에 안 잡히고 modifyScene 만
211
+ const after: any = applyScenePatch(initial, r.patch!)
212
212
  expect(after.sky).toBe('color')
213
213
  expect(after.skyColor).toBe('#0a1929')
214
214
  expect(after.exposure).toBe(0.7)
@@ -237,7 +237,7 @@ describe('통합 — removeComponentByRefid', () => {
237
237
  const a = new DefaultBoardAIAssistant(client)
238
238
  const r = await a.chat([{ role: 'user', content: '36 삭제' }], initial)
239
239
 
240
- const after = applyBoardEditPatch(initial, r.patch!)
240
+ const after = applyScenePatch(initial, r.patch!)
241
241
  expect(after.components).toHaveLength(2)
242
242
  expect(after.components.map((c: any) => c.refid)).toEqual([35, 37])
243
243
  })
@@ -265,7 +265,7 @@ describe('통합 — replaceBoard', () => {
265
265
  const a = new DefaultBoardAIAssistant(client)
266
266
  const r = await a.chat([{ role: 'user', content: '갈아엎어' }], initial)
267
267
 
268
- const after: any = applyBoardEditPatch(initial, r.patch!)
268
+ const after: any = applyScenePatch(initial, r.patch!)
269
269
  expect(after.width).toBe(1920)
270
270
  expect(after.height).toBe(1080)
271
271
  expect(after.fillStyle).toBe('#000')
@@ -296,7 +296,7 @@ describe('통합 — read-then-write 다중 turn', () => {
296
296
  expect(callLog).toHaveLength(3)
297
297
  expect(r.patch?.ops).toHaveLength(1) // read 는 patch 에 안 들어감
298
298
  expect(r.patch?.ops[0].op).toBe('modify')
299
- const after = applyBoardEditPatch(initial, r.patch!)
299
+ const after = applyScenePatch(initial, r.patch!)
300
300
  expect((after.components[0] as any).left).toBe(100)
301
301
  })
302
302
 
@@ -324,7 +324,7 @@ describe('통합 — read-then-write 다중 turn', () => {
324
324
  const r = await a.chat([{ role: 'user', content: 'rect 다 빨갛게' }], initial)
325
325
 
326
326
  expect(r.patch?.ops).toHaveLength(2)
327
- const after = applyBoardEditPatch(initial, r.patch!)
327
+ const after = applyScenePatch(initial, r.patch!)
328
328
  expect((after.components[0] as any).fillStyle).toBe('#ff0000') // rect
329
329
  expect((after.components[1] as any).fillStyle).toBe('#ff0000') // rect
330
330
  expect((after.components[2] as any).fillStyle).toBe('#fff') // circle 무영향
@@ -353,7 +353,7 @@ describe('통합 — write + action 혼합', () => {
353
353
  expect(r.actions![0]).toEqual({ action: 'setSceneMode', mode: 'view' })
354
354
 
355
355
  // apply-patch 는 patch.ops 만 처리 (actions 는 호스트가 별도 처리)
356
- const after = applyBoardEditPatch(initial, r.patch!)
356
+ const after = applyScenePatch(initial, r.patch!)
357
357
  expect((after.components[0] as any).left).toBe(100)
358
358
  })
359
359
 
@@ -393,11 +393,11 @@ describe('통합 — 다중 op 한 patch 안 순차 적용', () => {
393
393
  const a = new DefaultBoardAIAssistant(client)
394
394
  const r = await a.chat([{ role: 'user', content: 'circle 추가하고 1 left=50' }], initial)
395
395
 
396
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
396
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
397
397
  expect(verbose.applied).toHaveLength(2)
398
- expect(verbose.board.components).toHaveLength(2)
399
- expect((verbose.board.components[0] as any).left).toBe(50)
400
- expect((verbose.board.components[1] as any).type).toBe('circle')
398
+ expect(verbose.model.components).toHaveLength(2)
399
+ expect((verbose.model.components[0] as any).left).toBe(50)
400
+ expect((verbose.model.components[1] as any).type).toBe('circle')
401
401
  })
402
402
 
403
403
  test('일부 applied + 일부 missed 혼합', async () => {
@@ -415,10 +415,10 @@ describe('통합 — 다중 op 한 patch 안 순차 적용', () => {
415
415
  const a = new DefaultBoardAIAssistant(client)
416
416
  const r = await a.chat([{ role: 'user', content: 'do' }], initial)
417
417
 
418
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
418
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
419
419
  expect(verbose.applied).toHaveLength(2) // refid 1 modify + add
420
420
  expect(verbose.missed).toHaveLength(1) // refid 999 modify
421
- expect(verbose.board.components).toHaveLength(2)
421
+ expect(verbose.model.components).toHaveLength(2)
422
422
  })
423
423
  })
424
424
 
@@ -441,10 +441,10 @@ describe('통합 — Phase 2 scene 조작 op (모델 차원 noop, scene API 정
441
441
 
442
442
  expect(r.patch?.ops).toHaveLength(1)
443
443
  expect(r.patch?.ops[0]).toEqual({ op: 'align', refids: [1, 2], direction: 'left' })
444
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
444
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
445
445
  expect(verbose.applied).toHaveLength(1)
446
446
  expect(verbose.missed).toHaveLength(0)
447
- expect(verbose.board).toBe(initial) // model 차원에선 reference 동일
447
+ expect(verbose.model).toBe(initial) // model 차원에선 reference 동일
448
448
  })
449
449
 
450
450
  test('group + zorder 혼합', async () => {
@@ -465,7 +465,7 @@ describe('통합 — Phase 2 scene 조작 op (모델 차원 noop, scene API 정
465
465
  const r = await a.chat([{ role: 'user', content: '그룹 + 앞으로' }], initial)
466
466
 
467
467
  expect(r.patch?.ops).toHaveLength(2)
468
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
468
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
469
469
  expect(verbose.applied).toHaveLength(2)
470
470
  expect(verbose.missed).toHaveLength(0)
471
471
  })
@@ -482,7 +482,7 @@ describe('통합 — text-only 응답 (patch 없음)', () => {
482
482
  expect(r.patch).toBeUndefined()
483
483
  expect(r.actions).toBeUndefined()
484
484
  // 보드도 변경 없음
485
- const after = applyBoardEditPatch(initial, { ops: [], summary: '', confidence: 0 })
485
+ const after = applyScenePatch(initial, { ops: [], summary: '', confidence: 0 })
486
486
  expect(after).toBe(initial)
487
487
  })
488
488
  })
@@ -517,7 +517,7 @@ describe('통합 — Prefab (검증된 복합 컴포넌트 한 번에 추가)',
517
517
 
518
518
  expect(callLog).toHaveLength(3) // read → write → finalize
519
519
  expect(r.patch?.ops).toHaveLength(1) // addPrefab → 단일 add op
520
- const after = applyBoardEditPatch(initial, r.patch!)
520
+ const after = applyScenePatch(initial, r.patch!)
521
521
  expect(after.components).toHaveLength(1)
522
522
  const added: any = after.components[0]
523
523
  expect(added.type).toBe('group') // prefab 은 group 으로 wrapping
@@ -573,7 +573,7 @@ describe('통합 — Prefab (검증된 복합 컴포넌트 한 번에 추가)',
573
573
  const r = await a.chat([{ role: 'user', content: 'KPI 타일 3개' }], initial)
574
574
 
575
575
  expect(r.patch?.ops).toHaveLength(3)
576
- const after = applyBoardEditPatch(initial, r.patch!)
576
+ const after = applyScenePatch(initial, r.patch!)
577
577
  expect(after.components).toHaveLength(3)
578
578
  // 각 타일이 group 이고 fillStyle 이 다름 (옵션 반영)
579
579
  const fills = (after.components as any[])
@@ -582,7 +582,7 @@ describe('통합 — Prefab (검증된 복합 컴포넌트 한 번에 추가)',
582
582
  expect(fills).toEqual(['#0ea5e9', '#10b981', '#ef4444'])
583
583
  })
584
584
 
585
- test('잘못된 prefab name → patch 에 누락 (silent skip — toolCallToBoardEditOp 가 null 반환)', async () => {
585
+ test('잘못된 prefab name → patch 에 누락 (silent skip — toolCallToSceneEditOp 가 null 반환)', async () => {
586
586
  const initial = makeBoard()
587
587
  const { client } = makeMockClient([
588
588
  {
@@ -598,7 +598,7 @@ describe('통합 — Prefab (검증된 복합 컴포넌트 한 번에 추가)',
598
598
  ])
599
599
  const a = new DefaultBoardAIAssistant(client)
600
600
  const r = await a.chat([{ role: 'user', content: 'x' }], initial)
601
- // 잘못된 prefab → toolCallToBoardEditOp 가 null → patch 에 op 미추가
601
+ // 잘못된 prefab → toolCallToSceneEditOp 가 null → patch 에 op 미추가
602
602
  expect(r.patch).toBeUndefined()
603
603
  })
604
604
  })
@@ -622,7 +622,7 @@ describe('통합 — Design system 카탈로그 (color palette + layout template
622
622
  toolCalls: [
623
623
  {
624
624
  id: 'w1',
625
- name: 'modifyBoard',
625
+ name: 'modifyScene',
626
626
  arguments: { patch: { fillStyle: '#0f1722' } } // industrial-steel.base
627
627
  },
628
628
  {
@@ -663,7 +663,7 @@ describe('통합 — Design system 카탈로그 (color palette + layout template
663
663
  expect(readNames).toContain('getLayoutTemplates')
664
664
 
665
665
  // patch 적용 후 보드 배경 + 2 prefab tile
666
- const after: any = applyBoardEditPatch(initial, r.patch!)
666
+ const after: any = applyScenePatch(initial, r.patch!)
667
667
  expect(after.fillStyle).toBe('#0f1722') // industrial-steel.base
668
668
  expect(after.components).toHaveLength(2)
669
669
  // 모두 group prefab
@@ -868,10 +868,10 @@ describe('통합 — Sugar layout (arrange grid/row/column)', () => {
868
868
  expect(r.patch.ops[0].layout).toEqual({ type: 'grid', cols: 3 })
869
869
  }
870
870
  // model 차원 noop — 호스트가 정본 (board-edit-dispatch 가 위치 계산)
871
- const verbose = applyBoardEditPatchVerbose(initial, r.patch!)
871
+ const verbose = applyScenePatchVerbose(initial, r.patch!)
872
872
  expect(verbose.applied).toHaveLength(1)
873
873
  expect(verbose.missed).toHaveLength(0)
874
- expect(verbose.board).toBe(initial) // model 동일
874
+ expect(verbose.model).toBe(initial) // model 동일
875
875
  })
876
876
 
877
877
  test('"한 줄로 가운데 정렬" → arrangeInRow + align:center', async () => {
@@ -171,7 +171,7 @@ describeIf('LLM 스모크 — 실제 모델 tool 선택 검증', () => {
171
171
  )
172
172
 
173
173
  test(
174
- '"보드 배경 어둡게" → modifyBoard',
174
+ '"보드 배경 어둡게" → modifyScene',
175
175
  async () => {
176
176
  const a = new DefaultBoardAIAssistant(client)
177
177
  const r = await a.chat(
@@ -181,14 +181,14 @@ describeIf('LLM 스모크 — 실제 모델 tool 선택 검증', () => {
181
181
  )
182
182
  const names = (r.toolUsages ?? []).map((u: any) => u.name)
183
183
  dumpUsages(r.toolUsages)
184
- // modifyBoard 또는 atmosphere primer + modifyBoard 둘 다 OK
185
- expect(names).toContain('modifyBoard')
184
+ // modifyScene 또는 atmosphere primer + modifyScene 둘 다 OK
185
+ expect(names).toContain('modifyScene')
186
186
  },
187
187
  TIMEOUT_MS
188
188
  )
189
189
 
190
190
  test(
191
- '"심해 분위기로" → getAtmosphereGuide + modifyBoard 패턴',
191
+ '"심해 분위기로" → getAtmosphereGuide + modifyScene 패턴',
192
192
  async () => {
193
193
  const a = new DefaultBoardAIAssistant(client)
194
194
  const r = await a.chat(
@@ -200,7 +200,7 @@ describeIf('LLM 스모크 — 실제 모델 tool 선택 검증', () => {
200
200
  dumpUsages(r.toolUsages)
201
201
  // 핵심: AI 가 atmosphere primer 를 활용 (LLM 이 atmosphere 모르더라도 우리
202
202
  // primer 가이드를 호출해야 일관된 결과 — 시스템 프롬프트의 의도)
203
- expect(names).toContain('modifyBoard')
203
+ expect(names).toContain('modifyScene')
204
204
  },
205
205
  TIMEOUT_MS
206
206
  )