@things-factory/board-ai 10.1.6 → 10.1.8

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 (31) hide show
  1. package/client/index.ts +13 -1
  2. package/dist-client/client/index.js +13 -1
  3. package/dist-client/client/index.js.map +1 -1
  4. package/dist-client/server/service/assistant.js +17 -1
  5. package/dist-client/server/service/assistant.js.map +1 -1
  6. package/dist-client/server/service/types.d.ts +7 -0
  7. package/dist-client/server/service/types.js.map +1 -1
  8. package/dist-client/tsconfig.tsbuildinfo +1 -1
  9. package/dist-server/service/assistant.js +17 -1
  10. package/dist-server/service/assistant.js.map +1 -1
  11. package/dist-server/service/board-ai-resolver.d.ts +1 -0
  12. package/dist-server/service/board-ai-resolver.js +10 -2
  13. package/dist-server/service/board-ai-resolver.js.map +1 -1
  14. package/dist-server/service/board-session-resolver.js +3 -3
  15. package/dist-server/service/board-session-resolver.js.map +1 -1
  16. package/dist-server/service/types.d.ts +7 -0
  17. package/dist-server/service/types.js.map +1 -1
  18. package/dist-server/tsconfig.tsbuildinfo +1 -1
  19. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +15 -0
  20. package/logs/connections-2026-09-12-15.log +0 -0
  21. package/package.json +7 -7
  22. package/server/service/assistant.test.ts +5 -0
  23. package/server/service/assistant.ts +18 -1
  24. package/server/service/board-ai-resolver.ts +10 -2
  25. package/server/service/board-session-resolver.ts +3 -3
  26. package/server/service/types.ts +8 -0
  27. package/translations/en.json +1 -62
  28. package/translations/ja.json +1 -61
  29. package/translations/ko.json +1 -62
  30. package/translations/ms.json +1 -61
  31. package/translations/zh.json +1 -61
@@ -0,0 +1,15 @@
1
+ {
2
+ "keep": {
3
+ "days": true,
4
+ "amount": 14
5
+ },
6
+ "auditLog": "logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json",
7
+ "files": [
8
+ {
9
+ "date": 1789195002942,
10
+ "name": "logs/connections-2026-09-12-15.log",
11
+ "hash": "cf643fb0881a2a037b9657d9f0cab3f858825cbc597ef955ba6335a9305911c5"
12
+ }
13
+ ],
14
+ "hashType": "sha256"
15
+ }
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/board-ai",
3
- "version": "10.1.6",
3
+ "version": "10.1.8",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/client/index.js",
6
6
  "things-factory": true,
@@ -31,12 +31,12 @@
31
31
  "@operato/graphql": "^10.0.0",
32
32
  "@operato/i18n": "^10.0.0",
33
33
  "@operato/styles": "^10.0.0",
34
- "@things-factory/ai-assistant": "^10.1.6",
35
- "@things-factory/ai-client-base": "^10.1.6",
36
- "@things-factory/auth-base": "^10.1.6",
37
- "@things-factory/board-import": "^10.1.6",
34
+ "@things-factory/ai-assistant": "^10.1.8",
35
+ "@things-factory/ai-client-base": "^10.1.8",
36
+ "@things-factory/auth-base": "^10.1.7",
37
+ "@things-factory/board-import": "^10.1.8",
38
38
  "@things-factory/env": "^10.1.3",
39
- "@things-factory/shell": "^10.1.4",
39
+ "@things-factory/shell": "^10.1.7",
40
40
  "dompurify": "^3.0.0",
41
41
  "graphql-tag": "^2.12.6",
42
42
  "lit": "^3.1.2",
@@ -46,5 +46,5 @@
46
46
  "copyfiles": "^2.4.1",
47
47
  "rimraf": "^5.0.0"
48
48
  },
49
- "gitHead": "963aeb9ac470be5aea05bb5842a0a92afcab6036"
49
+ "gitHead": "c402982e29aab3b49e56bea4e41948be6a749c7f"
50
50
  }
@@ -19,6 +19,7 @@ import {
19
19
  buildBoardEditTools,
20
20
  DefaultBoardAIAssistant
21
21
  } from './assistant'
22
+ import { isGroundedAnalysisContract } from '@things-factory/ai-client-base'
22
23
 
23
24
  describe('toolCallToBoardEditOp', () => {
24
25
  test('addComponent: 정상 인자', () => {
@@ -1845,6 +1846,10 @@ describe('agentic loop (chatViaTools) — mock provider', () => {
1845
1846
  // result 는 summarized 객체
1846
1847
  expect(u.result.count).toBe(1)
1847
1848
  expect(u.result.selected[0].name).toBe('AGV-1')
1849
+ expect(isGroundedAnalysisContract(r.analysis)).toBe(true)
1850
+ expect(r.analysis?.kind).toBe('board.analysis.v1')
1851
+ expect(r.analysis?.approvalRequired).toBe(true)
1852
+ expect(r.analysis?.approval.mode).toBe('confirm')
1848
1853
  })
1849
1854
 
1850
1855
  test('toolUsages 수집 — write tool 은 queued 마커', async () => {
@@ -310,6 +310,22 @@ export class DefaultBoardAIAssistant implements BoardAIAssistant {
310
310
  toolResults: loopResult.groundedTexts
311
311
  })
312
312
 
313
+ const analysis = (toolUsages.length || patch || accumulatedActions.length || loopResult.proposals.length)
314
+ ? {
315
+ kind: 'board.analysis.v1' as const,
316
+ scope: { boardId: (currentBoard as any)?.id },
317
+ window: { turn: messages.length },
318
+ confidence: { level: warnings.length ? 'low' as const : 'medium' as const, reasons: warnings.length ? ['grounding-warning'] : ['tool-or-board-context'] },
319
+ limitations: warnings.map(code => ({ code })),
320
+ claims: [{ code: patch ? 'board.patch-proposed' : 'board.context-reviewed', severity: 'info' as const, evidence: { toolCalls: toolUsages.length, componentCount: components.length }, method: 'board-agentic-loop', assumptions: ['Board context is current for this turn.'] }],
321
+ facts: { board: boardContext, toolUsages },
322
+ ...(patch ? { proposal: patch } : accumulatedActions.length ? { proposal: accumulatedActions } : {}),
323
+ approvalRequired: true as const,
324
+ approval: { required: true as const, mode: 'confirm' as const, reason: patch || accumulatedActions.length ? 'Board or scene change requires user confirmation.' : 'Analysis is advisory.' },
325
+ trace: { source: 'board-ai', generatedAt: new Date().toISOString(), version: '1' }
326
+ }
327
+ : undefined
328
+
313
329
  return {
314
330
  reply,
315
331
  patch,
@@ -318,7 +334,8 @@ export class DefaultBoardAIAssistant implements BoardAIAssistant {
318
334
  actions: accumulatedActions.length > 0 ? accumulatedActions : undefined,
319
335
  /* 제안은 실행 전 상태다 — 대화면이 확인 버튼을 그린다. 서버는 실행하지 않는다. */
320
336
  proposals: loopResult.proposals.length > 0 ? loopResult.proposals : undefined,
321
- groundingWarnings: warnings.length > 0 ? warnings : undefined
337
+ groundingWarnings: warnings.length > 0 ? warnings : undefined,
338
+ analysis
322
339
  }
323
340
  }
324
341
 
@@ -245,6 +245,13 @@ class BoardAIChatOutput {
245
245
  'Ungrounded identifiers mentioned by the reply — present in the answer but absent from everything the model received (prompt, board context, history, tool results). Hallucination candidates surfaced to the user; the reply itself is not altered. Null when the answer is grounded.'
246
246
  })
247
247
  groundingWarnings?: any
248
+
249
+ @Field(() => GraphQLJSON, {
250
+ nullable: true,
251
+ description:
252
+ 'Grounded analysis contract for this turn: scope, evidence-backed claims, limitations, proposal and explicit approval boundary. Null when the turn did not perform an analysis.'
253
+ })
254
+ analysis?: any
248
255
  }
249
256
 
250
257
  @Resolver()
@@ -268,7 +275,7 @@ export class BoardAIChatResolver {
268
275
  * 가진 사람이 이 문으로 보드를 고치게 된다. 그래서 아래에서 **보드 편집 권한을 따로 보고**
269
276
  * 없으면 그 도구를 끈다(§`effectiveBoardTools`).
270
277
  */
271
- @Directive('@privilege(category: "ai-assistant", privilege: "mutation", legacy: "board-ai")')
278
+ @Directive('@privilege(category: "ai-assistant", privilege: "mutation")')
272
279
  async boardAIChat(
273
280
  @Arg('input') input: BoardAIChatInput,
274
281
  @Ctx() context: ResolverContext
@@ -513,7 +520,8 @@ export class BoardAIChatResolver {
513
520
  actions: r.actions && r.actions.length > 0 ? r.actions : null,
514
521
  proposals: r.proposals && r.proposals.length > 0 ? r.proposals : null,
515
522
  historyFolded: historyFolded ?? null,
516
- groundingWarnings: r.groundingWarnings && r.groundingWarnings.length > 0 ? r.groundingWarnings : null
523
+ groundingWarnings: r.groundingWarnings && r.groundingWarnings.length > 0 ? r.groundingWarnings : null,
524
+ analysis: r.analysis ?? null
517
525
  }
518
526
  }
519
527
 
@@ -39,7 +39,7 @@ const sessions = new ChatSessionResolver()
39
39
  @Resolver()
40
40
  export class BoardSessionResolver {
41
41
  @Query(() => ChatSession, { nullable: true, description: 'Get AI chat session by board id (returns first match — backward compat single-session lookup).' })
42
- @Directive('@privilege(category: "ai-assistant", privilege: "query", legacy: "board-ai")')
42
+ @Directive('@privilege(category: "ai-assistant", privilege: "query")')
43
43
  async chatSessionByBoard(
44
44
  @Arg('boardId') boardId: string,
45
45
  @Ctx() context: ResolverContext
@@ -54,7 +54,7 @@ export class BoardSessionResolver {
54
54
  @Query(() => [ChatSession], {
55
55
  description: 'List all AI chat sessions for a board (oldest first). Thin wrapper over chatSessionsByAnchor(board).'
56
56
  })
57
- @Directive('@privilege(category: "ai-assistant", privilege: "query", legacy: "board-ai")')
57
+ @Directive('@privilege(category: "ai-assistant", privilege: "query")')
58
58
  async chatSessionsByBoard(
59
59
  @Arg('boardId') boardId: string,
60
60
  @Ctx() context: ResolverContext
@@ -95,7 +95,7 @@ export class BoardSessionResolver {
95
95
  @Mutation(() => ChatSession, {
96
96
  description: 'Start (or get existing) AI chat session for a board. Thin wrapper over startAISession(board).'
97
97
  })
98
- @Directive('@privilege(category: "ai-assistant", privilege: "mutation", legacy: "board-ai")')
98
+ @Directive('@privilege(category: "ai-assistant", privilege: "mutation")')
99
99
  async startBoardAISession(
100
100
  @Arg('boardId') boardId: string,
101
101
  @Ctx() context: ResolverContext
@@ -117,8 +117,14 @@ export interface ComponentSchema {
117
117
  * import 를 그대로 두기 위해서다 — 뜻의 정본은 저쪽 한 곳이다.
118
118
  */
119
119
  import type { ToolUsage } from '@things-factory/ai-client-base'
120
+ import type { AIAnalysisClaim, GroundedAnalysisContract } from '@things-factory/ai-client-base'
120
121
  export type { ToolUsage }
121
122
 
123
+ /** Board-specific extension of the shared evidence/approval analysis boundary. */
124
+ export interface BoardGroundedAnalysis extends GroundedAnalysisContract<any, AIAnalysisClaim, BoardEditPatch | BoardActionOp[]> {
125
+ kind: 'board.analysis.v1'
126
+ }
127
+
122
128
 
123
129
  export interface ChatResponse {
124
130
  /** 사용자에게 보여줄 텍스트 응답 */
@@ -148,6 +154,8 @@ export interface ChatResponse {
148
154
  * 판정 규칙·사정거리는 ./grounding 참조. 비면(undefined) 접지 정상.
149
155
  */
150
156
  groundingWarnings?: string[]
157
+ /** Present when the turn inspected state or proposed a board/action change. */
158
+ analysis?: BoardGroundedAnalysis
151
159
  }
152
160
 
153
161
  export interface BoardEditPatch {
@@ -1,64 +1,3 @@
1
1
  {
2
- "board-ai.label.ai": "operato",
3
- "board-ai.label.participant": "participant",
4
- "board-ai.label.create": "Create",
5
- "board-ai.label.edit": "Edit",
6
- "board-ai.label.style": "Style",
7
- "board-ai.label.korean-supported": "Korean / English",
8
- "board-ai.label.multi-command": "Batch commands",
9
- "board-ai.label.review-able": "Reviewable",
10
-
11
- "board-ai.text.empty-title": "Design a board together with AI",
12
- "board-ai.text.empty-subtitle": "Describe in natural language and AI will create, edit, and style the board. Click an example below to begin.",
13
- "board-ai.text.empty-footer-notice": "AI responses are previewed on the board and can be reverted before final apply.",
14
- "board-ai.text.input-placeholder": "Describe what you want — # component · @ catalog · / template autocomplete",
15
- "board-ai.text.triggers-heading": "Or jump in with autocomplete",
16
- "board-ai.text.trigger-component-tooltip": "Mention a component on the board",
17
- "board-ai.text.trigger-user-tooltip": "Mention a domain teammate",
18
- "board-ai.text.trigger-insert-tooltip": "Insert prefab / palette / layout / command template",
19
- "board-ai.text.send-tooltip": "Send (Enter)",
20
- "board-ai.text.show-examples-tooltip": "Show common command examples",
21
- "board-ai.text.applied-changes": "Applied.",
22
- "board-ai.text.reverted": "Reverted",
23
- "board-ai.text.failed-to-load-history": "Failed to load history",
24
- "board-ai.text.empty-response": "Empty response.",
25
-
26
- "board-ai.example.create-monitoring-dashboard": "Monitoring dashboard with 3 gauges (utilization, temperature, pressure) and a 24-hour line chart",
27
- "board-ai.example.create-welcome-screen": "Welcome screen with a large 'OPERATO' title, a clock, and a subtitle",
28
- "board-ai.example.edit-align-distribute": "Center-align the selected components and distribute evenly",
29
- "board-ai.example.edit-resize-board": "Resize the board to 1920x1080 and center the components",
30
- "board-ai.example.style-dark-mode": "Dark mode — deep navy background, white text, teal accents",
31
- "board-ai.example.style-rounded-shadow": "Round all shape corners and add a soft card shadow",
32
-
33
- "board-ai.button.new-chat": "New chat",
34
- "board-ai.label.trigger-component": "Component",
35
- "board-ai.label.trigger-user": "User",
36
- "board-ai.label.trigger-insert": "Insert",
37
- "board-ai.button.examples": "Examples",
38
- "board-ai.button.close": "Close",
39
- "board-ai.button.revert": "Revert",
40
- "board-ai.button.retry": "Retry",
41
- "board-ai.button.copy": "Copy",
42
- "board-ai.button.regenerate": "Regenerate",
43
- "board-ai.button.edit": "Edit",
44
-
45
- "board-ai.text.copied": "Copied",
46
- "board-ai.text.mention-not-found": "#{token} not found",
47
- "board-ai.text.session-tab-label": "Session {n}",
48
- "board-ai.text.tools-used": "Tools used",
49
- "board-ai.text.tool-turn": "decision {n}",
50
- "board-ai.text.tool-rejected-count": "rejected {count}",
51
- "board-ai.text.tool-folded-count": "folded {count}",
52
- "board-ai.text.outcome-ok": "read",
53
- "board-ai.text.outcome-rejected": "rejected",
54
- "board-ai.text.outcome-queued": "to apply",
55
- "board-ai.text.outcome-proposed": "proposed",
56
- "board-ai.text.outcome-folded": "duplicate",
57
- "board-ai.text.outcome-error": "error",
58
- "board-ai.text.ungrounded-mention": "Mentions an unverified target — not present in the actual data:",
59
- "board-ai.text.toggle-system-note": "click to expand",
60
- "board-ai.button.run-proposal": "run",
61
- "board-ai.text.proposal-sent": "execution requested",
62
- "board-ai.text.history-folded": "this conversation grew long — the earlier {count} messages were left out. a new conversation is better for a different topic.",
63
- "board-ai.text.history-folded-summarized": "this conversation grew long — the earlier {count} messages were folded into a summary. a new conversation is better for a different topic."
2
+ "board-ai.text.preview-before-apply": "AI responses are previewed on the board and can be reverted before final apply."
64
3
  }
@@ -1,63 +1,3 @@
1
1
  {
2
- "board-ai.label.ai": "operato",
3
- "board-ai.label.create": "作成",
4
- "board-ai.label.edit": "編集",
5
- "board-ai.label.style": "スタイル",
6
- "board-ai.label.korean-supported": "多言語対応",
7
- "board-ai.label.multi-command": "複数命令",
8
- "board-ai.label.review-able": "レビュー可能",
9
-
10
- "board-ai.text.empty-title": "AI と一緒にボードを作成しましょう",
11
- "board-ai.text.empty-subtitle": "自然言語で指示すると AI がボードを作成・編集・スタイリングします。下の例をクリックして始めてください。",
12
- "board-ai.text.empty-footer-notice": "AI の応答は適用前にプレビューで確認でき、元に戻すこともできます。",
13
- "board-ai.text.input-placeholder": "自然言語で指示してください (Shift+Enter で改行、Enter で送信)",
14
- "board-ai.text.triggers-heading": "または自動補完で素早く開始",
15
- "board-ai.text.trigger-component-tooltip": "ボードのコンポーネントをメンション",
16
- "board-ai.text.trigger-user-tooltip": "ドメイン内のメンバーをメンション",
17
- "board-ai.text.trigger-insert-tooltip": "プリファブ / パレット / レイアウト / 命令テンプレートを挿入",
18
- "board-ai.text.send-tooltip": "送信 (Enter)",
19
- "board-ai.text.show-examples-tooltip": "よく使う指示の例を表示",
20
- "board-ai.text.applied-changes": "変更しました。",
21
- "board-ai.text.reverted": "戻しました",
22
- "board-ai.text.failed-to-load-history": "履歴の読み込みに失敗",
23
- "board-ai.text.empty-response": "応答が空です。",
24
-
25
- "board-ai.example.create-monitoring-dashboard": "稼働率・温度・圧力の 3 ゲージと 24 時間のラインチャートで監視ダッシュボード",
26
- "board-ai.example.create-welcome-screen": "大きな「OPERATO」タイトルと時計、サブタイトルでウェルカム画面",
27
- "board-ai.example.edit-align-distribute": "選択したコンポーネントを中央揃えし均等配置",
28
- "board-ai.example.edit-resize-board": "ボードを 1920x1080 にしてコンポーネントを中央寄せ",
29
- "board-ai.example.style-dark-mode": "ダークモード — 濃紺の背景、白文字、ティール アクセント",
30
- "board-ai.example.style-rounded-shadow": "すべての図形を角丸にしてカード風の柔らかい影を追加",
31
-
32
- "board-ai.button.new-chat": "新しいチャット",
33
- "board-ai.label.trigger-component": "コンポーネント",
34
- "board-ai.label.trigger-user": "ユーザー",
35
- "board-ai.label.trigger-insert": "挿入",
36
- "board-ai.button.examples": "例",
37
- "board-ai.button.close": "閉じる",
38
- "board-ai.button.revert": "元に戻す",
39
- "board-ai.button.retry": "再試行",
40
- "board-ai.button.copy": "コピー",
41
- "board-ai.button.regenerate": "再生成",
42
- "board-ai.button.edit": "編集",
43
-
44
- "board-ai.text.copied": "コピーしました",
45
- "board-ai.text.mention-not-found": "#{token} が見つかりません",
46
- "board-ai.text.session-tab-label": "セッション {n}",
47
- "board-ai.text.tools-used": "使用したツール",
48
- "board-ai.text.tool-turn": "{n} 回目の判断",
49
- "board-ai.text.tool-rejected-count": "却下 {count}",
50
- "board-ai.text.tool-folded-count": "重複 {count}",
51
- "board-ai.text.outcome-ok": "照会",
52
- "board-ai.text.outcome-rejected": "却下",
53
- "board-ai.text.outcome-queued": "適用予定",
54
- "board-ai.text.outcome-proposed": "提案",
55
- "board-ai.text.outcome-folded": "重複",
56
- "board-ai.text.outcome-error": "エラー",
57
- "board-ai.text.ungrounded-mention": "確認できない対象に言及しています — 実データにありません:",
58
- "board-ai.text.toggle-system-note": "クリックで展開",
59
- "board-ai.button.run-proposal": "実行",
60
- "board-ai.text.proposal-sent": "実行を依頼しました",
61
- "board-ai.text.history-folded": "会話が長くなり、前半の {count} 件は省略されました。別の話題なら新しい会話のほうが適しています。",
62
- "board-ai.text.history-folded-summarized": "会話が長くなり、前半の {count} 件は要約にまとめられました。別の話題なら新しい会話のほうが適しています。"
2
+ "board-ai.text.preview-before-apply": "AI の応答は適用前にプレビューで確認でき、元に戻すこともできます。"
63
3
  }
@@ -1,64 +1,3 @@
1
1
  {
2
- "board-ai.label.ai": "operato",
3
- "board-ai.label.participant": "참여자",
4
- "board-ai.label.create": "생성",
5
- "board-ai.label.edit": "편집",
6
- "board-ai.label.style": "스타일",
7
- "board-ai.label.korean-supported": "한국어 자유",
8
- "board-ai.label.multi-command": "다중 명령",
9
- "board-ai.label.review-able": "검수 가능",
10
-
11
- "board-ai.text.empty-title": "AI 와 함께 보드를 만들어보세요",
12
- "board-ai.text.empty-subtitle": "자연어로 명령하시면 AI 가 보드를 생성·편집·스타일링합니다. 아래 예시를 클릭해 시작해보세요.",
13
- "board-ai.text.empty-footer-notice": "AI 응답은 항상 보드에 적용 전 미리보기로 확인 가능합니다.",
14
- "board-ai.text.input-placeholder": "자연어 명령 — # 컴포넌트 · @ 카탈로그 · / 템플릿 자동완성",
15
- "board-ai.text.triggers-heading": "또는 자동완성으로 빠르게 시작",
16
- "board-ai.text.trigger-component-tooltip": "보드의 컴포넌트를 검색해 멘션",
17
- "board-ai.text.trigger-user-tooltip": "도메인 동료를 멘션",
18
- "board-ai.text.trigger-insert-tooltip": "프리팹 / 팔레트 / 레이아웃 / 명령 템플릿 삽입",
19
- "board-ai.text.send-tooltip": "전송 (Enter)",
20
- "board-ai.text.show-examples-tooltip": "자주 쓰는 명령 예시 보기",
21
- "board-ai.text.applied-changes": "변경했습니다.",
22
- "board-ai.text.reverted": "되돌려짐",
23
- "board-ai.text.failed-to-load-history": "이력 로드 실패",
24
- "board-ai.text.empty-response": "응답이 비어있습니다.",
25
- "board-ai.text.tools-used": "도구 사용",
26
- "board-ai.text.tool-turn": "{n}번째 판단",
27
- "board-ai.text.tool-rejected-count": "거절 {count}",
28
- "board-ai.text.tool-folded-count": "접힘 {count}",
29
- "board-ai.text.outcome-ok": "조회",
30
- "board-ai.text.outcome-rejected": "거절",
31
- "board-ai.text.outcome-queued": "적용 예정",
32
- "board-ai.text.outcome-proposed": "제안",
33
- "board-ai.text.outcome-folded": "중복 접힘",
34
- "board-ai.text.outcome-error": "오류",
35
- "board-ai.text.ungrounded-mention": "확인되지 않은 대상을 언급했습니다 — 실제 데이터에 없습니다:",
36
- "board-ai.text.toggle-system-note": "눌러서 펼치기",
37
- "board-ai.button.run-proposal": "실행",
38
- "board-ai.text.proposal-sent": "실행 요청됨",
39
- "board-ai.text.history-folded": "대화가 길어져 앞부분 {count}개가 생략되었습니다. 다른 주제라면 새 대화가 낫습니다.",
40
- "board-ai.text.history-folded-summarized": "대화가 길어져 앞부분 {count}개가 요약으로 접혔습니다. 다른 주제라면 새 대화가 낫습니다.",
41
-
42
- "board-ai.example.create-monitoring-dashboard": "가동률·온도·압력 3개 게이지와 24시간 라인 차트로 모니터링 대시보드",
43
- "board-ai.example.create-welcome-screen": "큰 'OPERATO' 제목과 시계, 부제로 환영 화면",
44
- "board-ai.example.edit-align-distribute": "선택한 컴포넌트들을 가운데 정렬하고 일정 간격으로 분산",
45
- "board-ai.example.edit-resize-board": "보드 크기를 1920x1080 으로 변경하고 컴포넌트 중앙 정렬",
46
- "board-ai.example.style-dark-mode": "다크 모드 — 짙은 남색 배경, 흰색 텍스트, 청록 강조",
47
- "board-ai.example.style-rounded-shadow": "모든 도형 모서리 둥글게 + 카드형 옅은 그림자",
48
-
49
- "board-ai.button.new-chat": "새 대화",
50
- "board-ai.label.trigger-component": "컴포넌트",
51
- "board-ai.label.trigger-user": "사용자",
52
- "board-ai.label.trigger-insert": "삽입",
53
- "board-ai.button.examples": "예시",
54
- "board-ai.button.close": "닫기",
55
- "board-ai.button.revert": "되돌리기",
56
- "board-ai.button.retry": "다시 시도",
57
- "board-ai.button.copy": "복사",
58
- "board-ai.button.regenerate": "재생성",
59
- "board-ai.button.edit": "편집",
60
-
61
- "board-ai.text.copied": "복사됨",
62
- "board-ai.text.mention-not-found": "#{token} 을(를) 찾을 수 없습니다",
63
- "board-ai.text.session-tab-label": "세션 {n}"
2
+ "board-ai.text.preview-before-apply": "AI 응답은 항상 보드에 적용 전 미리보기로 확인 가능합니다."
64
3
  }
@@ -1,63 +1,3 @@
1
1
  {
2
- "board-ai.label.ai": "operato",
3
- "board-ai.label.create": "Cipta",
4
- "board-ai.label.edit": "Edit",
5
- "board-ai.label.style": "Gaya",
6
- "board-ai.label.korean-supported": "Pelbagai bahasa",
7
- "board-ai.label.multi-command": "Arahan kumpulan",
8
- "board-ai.label.review-able": "Boleh disemak",
9
-
10
- "board-ai.text.empty-title": "Reka papan bersama AI",
11
- "board-ai.text.empty-subtitle": "Terangkan dalam bahasa biasa dan AI akan mencipta, mengedit dan menggayakan papan. Klik contoh di bawah untuk bermula.",
12
- "board-ai.text.empty-footer-notice": "Respons AI dipratonton sebelum diterapkan dan boleh dibatalkan.",
13
- "board-ai.text.input-placeholder": "Terangkan dalam bahasa biasa (Shift+Enter baris baharu, Enter hantar)",
14
- "board-ai.text.triggers-heading": "Atau mula pantas dengan auto-lengkap",
15
- "board-ai.text.trigger-component-tooltip": "Sebut komponen pada papan",
16
- "board-ai.text.trigger-user-tooltip": "Sebut rakan domain",
17
- "board-ai.text.trigger-insert-tooltip": "Sisip prefab / palet / susun atur / templat arahan",
18
- "board-ai.text.send-tooltip": "Hantar (Enter)",
19
- "board-ai.text.show-examples-tooltip": "Tunjuk contoh arahan biasa",
20
- "board-ai.text.applied-changes": "Diterapkan.",
21
- "board-ai.text.reverted": "Dibatalkan",
22
- "board-ai.text.failed-to-load-history": "Gagal memuatkan sejarah",
23
- "board-ai.text.empty-response": "Respons kosong.",
24
-
25
- "board-ai.example.create-monitoring-dashboard": "Papan pemantauan dengan 3 tolok (penggunaan, suhu, tekanan) dan carta garis 24 jam",
26
- "board-ai.example.create-welcome-screen": "Skrin selamat datang dengan tajuk besar 'OPERATO', jam dan sari kata",
27
- "board-ai.example.edit-align-distribute": "Jajarkan komponen terpilih ke tengah dan agih sama rata",
28
- "board-ai.example.edit-resize-board": "Ubah saiz papan kepada 1920x1080 dan tengahkan komponen",
29
- "board-ai.example.style-dark-mode": "Mod gelap — latar biru tua, teks putih, aksen teal",
30
- "board-ai.example.style-rounded-shadow": "Bulatkan sudut semua bentuk + bayang kad lembut",
31
-
32
- "board-ai.button.new-chat": "Sembang baharu",
33
- "board-ai.label.trigger-component": "Komponen",
34
- "board-ai.label.trigger-user": "Pengguna",
35
- "board-ai.label.trigger-insert": "Sisip",
36
- "board-ai.button.examples": "Contoh",
37
- "board-ai.button.close": "Tutup",
38
- "board-ai.button.revert": "Batalkan",
39
- "board-ai.button.retry": "Cuba lagi",
40
- "board-ai.button.copy": "Salin",
41
- "board-ai.button.regenerate": "Jana semula",
42
- "board-ai.button.edit": "Edit",
43
-
44
- "board-ai.text.copied": "Disalin",
45
- "board-ai.text.mention-not-found": "#{token} tidak dijumpai",
46
- "board-ai.text.session-tab-label": "Sesi {n}",
47
- "board-ai.text.tools-used": "Alat yang digunakan",
48
- "board-ai.text.tool-turn": "keputusan {n}",
49
- "board-ai.text.tool-rejected-count": "ditolak {count}",
50
- "board-ai.text.tool-folded-count": "pendua {count}",
51
- "board-ai.text.outcome-ok": "baca",
52
- "board-ai.text.outcome-rejected": "ditolak",
53
- "board-ai.text.outcome-queued": "akan digunakan",
54
- "board-ai.text.outcome-proposed": "dicadangkan",
55
- "board-ai.text.outcome-folded": "pendua",
56
- "board-ai.text.outcome-error": "ralat",
57
- "board-ai.text.ungrounded-mention": "Menyebut sasaran yang tidak disahkan — tiada dalam data sebenar:",
58
- "board-ai.text.toggle-system-note": "klik untuk kembangkan",
59
- "board-ai.button.run-proposal": "jalankan",
60
- "board-ai.text.proposal-sent": "pelaksanaan diminta",
61
- "board-ai.text.history-folded": "perbualan ini menjadi panjang — {count} mesej terawal ditinggalkan. perbualan baharu lebih sesuai untuk topik lain.",
62
- "board-ai.text.history-folded-summarized": "perbualan ini menjadi panjang — {count} mesej terawal diringkaskan. perbualan baharu lebih sesuai untuk topik lain."
2
+ "board-ai.text.preview-before-apply": "Respons AI dipratonton sebelum diterapkan dan boleh dibatalkan."
63
3
  }
@@ -1,63 +1,3 @@
1
1
  {
2
- "board-ai.label.ai": "operato",
3
- "board-ai.label.create": "创建",
4
- "board-ai.label.edit": "编辑",
5
- "board-ai.label.style": "样式",
6
- "board-ai.label.korean-supported": "多语言",
7
- "board-ai.label.multi-command": "批量命令",
8
- "board-ai.label.review-able": "可审核",
9
-
10
- "board-ai.text.empty-title": "与 AI 一起设计看板",
11
- "board-ai.text.empty-subtitle": "用自然语言描述,AI 将创建、编辑和样式化看板。点击下方示例开始。",
12
- "board-ai.text.empty-footer-notice": "AI 的响应在应用前会先预览,并可以撤销。",
13
- "board-ai.text.input-placeholder": "用自然语言描述 (Shift+Enter 换行, Enter 发送)",
14
- "board-ai.text.triggers-heading": "或用自动完成快速开始",
15
- "board-ai.text.trigger-component-tooltip": "提及看板上的组件",
16
- "board-ai.text.trigger-user-tooltip": "提及域内同事",
17
- "board-ai.text.trigger-insert-tooltip": "插入预制 / 调色板 / 布局 / 命令模板",
18
- "board-ai.text.send-tooltip": "发送 (Enter)",
19
- "board-ai.text.show-examples-tooltip": "显示常用命令示例",
20
- "board-ai.text.applied-changes": "已应用。",
21
- "board-ai.text.reverted": "已撤销",
22
- "board-ai.text.failed-to-load-history": "加载历史失败",
23
- "board-ai.text.empty-response": "响应为空。",
24
-
25
- "board-ai.example.create-monitoring-dashboard": "用稼动率、温度、压力 3 个仪表 + 24 小时折线图制作监控看板",
26
- "board-ai.example.create-welcome-screen": "用大号 'OPERATO' 标题、时钟、副标题做欢迎画面",
27
- "board-ai.example.edit-align-distribute": "将所选组件居中对齐并均匀分布",
28
- "board-ai.example.edit-resize-board": "看板调整为 1920x1080 并将组件居中",
29
- "board-ai.example.style-dark-mode": "深色模式 — 深蓝背景、白色文字、青色强调",
30
- "board-ai.example.style-rounded-shadow": "所有图形圆角 + 柔和卡片阴影",
31
-
32
- "board-ai.button.new-chat": "新对话",
33
- "board-ai.label.trigger-component": "组件",
34
- "board-ai.label.trigger-user": "用户",
35
- "board-ai.label.trigger-insert": "插入",
36
- "board-ai.button.examples": "示例",
37
- "board-ai.button.close": "关闭",
38
- "board-ai.button.revert": "撤销",
39
- "board-ai.button.retry": "重试",
40
- "board-ai.button.copy": "复制",
41
- "board-ai.button.regenerate": "重新生成",
42
- "board-ai.button.edit": "编辑",
43
-
44
- "board-ai.text.copied": "已复制",
45
- "board-ai.text.mention-not-found": "未找到 #{token}",
46
- "board-ai.text.session-tab-label": "会话 {n}",
47
- "board-ai.text.tools-used": "使用的工具",
48
- "board-ai.text.tool-turn": "第 {n} 次判断",
49
- "board-ai.text.tool-rejected-count": "拒绝 {count}",
50
- "board-ai.text.tool-folded-count": "折叠 {count}",
51
- "board-ai.text.outcome-ok": "查询",
52
- "board-ai.text.outcome-rejected": "拒绝",
53
- "board-ai.text.outcome-queued": "待应用",
54
- "board-ai.text.outcome-proposed": "提案",
55
- "board-ai.text.outcome-folded": "重复",
56
- "board-ai.text.outcome-error": "错误",
57
- "board-ai.text.ungrounded-mention": "提到了未经确认的对象 — 实际数据中不存在:",
58
- "board-ai.text.toggle-system-note": "点击展开",
59
- "board-ai.button.run-proposal": "执行",
60
- "board-ai.text.proposal-sent": "已请求执行",
61
- "board-ai.text.history-folded": "对话变长,前面 {count} 条已省略。若是另一个话题,新建对话更合适。",
62
- "board-ai.text.history-folded-summarized": "对话变长,前面 {count} 条已折叠为摘要。若是另一个话题,新建对话更合适。"
2
+ "board-ai.text.preview-before-apply": "AI 的响应在应用前会先预览,并可以撤销。"
63
3
  }