@things-factory/ai-assistant 10.1.212 → 10.1.214

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 (127) hide show
  1. package/client/components/assistant-chat.ts +115 -2
  2. package/client/components/assistant-dock.ts +106 -3
  3. package/client/components/assistant-selection-bar.test.ts +42 -0
  4. package/client/components/assistant-selection-bar.ts +129 -0
  5. package/client/components/workspace-view.ts +56 -3
  6. package/client/index.ts +5 -0
  7. package/client/utils/assistant-ask.test.ts +38 -0
  8. package/client/utils/assistant-ask.ts +35 -1
  9. package/client/utils/assistant-proposals.ts +23 -0
  10. package/client/utils/assistant-selection.test.ts +54 -0
  11. package/client/utils/assistant-selection.ts +74 -0
  12. package/client/utils/assistant-session-controller.ts +2 -0
  13. package/client/utils/assistant-session-transport.ts +1 -1
  14. package/client/utils/invite-proposal-register.ts +31 -0
  15. package/client/utils/invite-proposal.test.ts +40 -0
  16. package/client/utils/invite-proposal.ts +54 -0
  17. package/dist-client/components/assistant-chat.d.ts +18 -0
  18. package/dist-client/components/assistant-chat.js +117 -2
  19. package/dist-client/components/assistant-chat.js.map +1 -1
  20. package/dist-client/components/assistant-dock.d.ts +11 -0
  21. package/dist-client/components/assistant-dock.js +97 -4
  22. package/dist-client/components/assistant-dock.js.map +1 -1
  23. package/dist-client/components/assistant-selection-bar.d.ts +44 -0
  24. package/dist-client/components/assistant-selection-bar.js +149 -0
  25. package/dist-client/components/assistant-selection-bar.js.map +1 -0
  26. package/dist-client/components/assistant-selection-bar.test.d.ts +1 -0
  27. package/dist-client/components/assistant-selection-bar.test.js +38 -0
  28. package/dist-client/components/assistant-selection-bar.test.js.map +1 -0
  29. package/dist-client/components/workspace-view.d.ts +2 -0
  30. package/dist-client/components/workspace-view.js +58 -3
  31. package/dist-client/components/workspace-view.js.map +1 -1
  32. package/dist-client/index.d.ts +3 -0
  33. package/dist-client/index.js +5 -0
  34. package/dist-client/index.js.map +1 -1
  35. package/dist-client/tsconfig.tsbuildinfo +1 -1
  36. package/dist-client/utils/assistant-ask.d.ts +22 -1
  37. package/dist-client/utils/assistant-ask.js +19 -0
  38. package/dist-client/utils/assistant-ask.js.map +1 -1
  39. package/dist-client/utils/assistant-ask.test.d.ts +1 -0
  40. package/dist-client/utils/assistant-ask.test.js +40 -0
  41. package/dist-client/utils/assistant-ask.test.js.map +1 -0
  42. package/dist-client/utils/assistant-proposals.d.ts +14 -0
  43. package/dist-client/utils/assistant-proposals.js +7 -0
  44. package/dist-client/utils/assistant-proposals.js.map +1 -1
  45. package/dist-client/utils/assistant-selection.d.ts +43 -0
  46. package/dist-client/utils/assistant-selection.js +59 -0
  47. package/dist-client/utils/assistant-selection.js.map +1 -0
  48. package/dist-client/utils/assistant-selection.test.d.ts +1 -0
  49. package/dist-client/utils/assistant-selection.test.js +46 -0
  50. package/dist-client/utils/assistant-selection.test.js.map +1 -0
  51. package/dist-client/utils/assistant-session-controller.d.ts +2 -0
  52. package/dist-client/utils/assistant-session-controller.js.map +1 -1
  53. package/dist-client/utils/assistant-session-transport.js +1 -1
  54. package/dist-client/utils/assistant-session-transport.js.map +1 -1
  55. package/dist-client/utils/invite-proposal-register.d.ts +1 -0
  56. package/dist-client/utils/invite-proposal-register.js +24 -0
  57. package/dist-client/utils/invite-proposal-register.js.map +1 -0
  58. package/dist-client/utils/invite-proposal.d.ts +17 -0
  59. package/dist-client/utils/invite-proposal.js +37 -0
  60. package/dist-client/utils/invite-proposal.js.map +1 -0
  61. package/dist-client/utils/invite-proposal.test.d.ts +1 -0
  62. package/dist-client/utils/invite-proposal.test.js +35 -0
  63. package/dist-client/utils/invite-proposal.test.js.map +1 -0
  64. package/dist-server/service/assistant-chat-resolver.js +7 -3
  65. package/dist-server/service/assistant-chat-resolver.js.map +1 -1
  66. package/dist-server/service/assistant-mode/index.d.ts +2 -1
  67. package/dist-server/service/assistant-mode/index.js +6 -1
  68. package/dist-server/service/assistant-mode/index.js.map +1 -1
  69. package/dist-server/service/assistant-mode/mode-categories.d.ts +29 -1
  70. package/dist-server/service/assistant-mode/mode-categories.js +57 -5
  71. package/dist-server/service/assistant-mode/mode-categories.js.map +1 -1
  72. package/dist-server/service/assistant-mode/screen-rules.d.ts +6 -0
  73. package/dist-server/service/assistant-mode/screen-rules.js +21 -6
  74. package/dist-server/service/assistant-mode/screen-rules.js.map +1 -1
  75. package/dist-server/service/data-read/read-target.d.ts +24 -3
  76. package/dist-server/service/data-read/read-target.js +42 -10
  77. package/dist-server/service/data-read/read-target.js.map +1 -1
  78. package/dist-server/service/data-read/read-tools.d.ts +18 -1
  79. package/dist-server/service/data-read/read-tools.js +19 -5
  80. package/dist-server/service/data-read/read-tools.js.map +1 -1
  81. package/dist-server/service/index.d.ts +5 -1
  82. package/dist-server/service/index.js +10 -1
  83. package/dist-server/service/index.js.map +1 -1
  84. package/dist-server/service/people/index.d.ts +4 -0
  85. package/dist-server/service/people/index.js +22 -0
  86. package/dist-server/service/people/index.js.map +1 -0
  87. package/dist-server/service/people/invite-tools.d.ts +34 -0
  88. package/dist-server/service/people/invite-tools.js +144 -0
  89. package/dist-server/service/people/invite-tools.js.map +1 -0
  90. package/dist-server/service/people/people-keys.d.ts +8 -0
  91. package/dist-server/service/people/people-keys.js +16 -0
  92. package/dist-server/service/people/people-keys.js.map +1 -0
  93. package/dist-server/service/people/people-read.d.ts +4 -0
  94. package/dist-server/service/people/people-read.js +57 -0
  95. package/dist-server/service/people/people-read.js.map +1 -0
  96. package/dist-server/service/testing/mode-conformance.js +3 -0
  97. package/dist-server/service/testing/mode-conformance.js.map +1 -1
  98. package/dist-server/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +6 -6
  100. package/server/service/assistant-chat-resolver.ts +8 -4
  101. package/server/service/assistant-mode/conversation-category.test.ts +35 -0
  102. package/server/service/assistant-mode/index.ts +3 -1
  103. package/server/service/assistant-mode/mode-categories.ts +72 -5
  104. package/server/service/assistant-mode/mode-front.test.ts +32 -4
  105. package/server/service/assistant-mode/resolve.test.ts +1 -1
  106. package/server/service/assistant-mode/screen-rules.test.ts +23 -1
  107. package/server/service/assistant-mode/screen-rules.ts +22 -5
  108. package/server/service/data-entry/data-entry.test.ts +2 -2
  109. package/server/service/data-read/detail-lists.test.ts +61 -0
  110. package/server/service/data-read/read-target.ts +54 -9
  111. package/server/service/data-read/read-tools.ts +32 -6
  112. package/server/service/index.ts +7 -1
  113. package/server/service/people/index.ts +13 -0
  114. package/server/service/people/invite-tools.ts +159 -0
  115. package/server/service/people/invite.test.ts +159 -0
  116. package/server/service/people/people-keys.ts +16 -0
  117. package/server/service/people/people-read.test.ts +82 -0
  118. package/server/service/people/people-read.ts +56 -0
  119. package/server/service/testing/mode-conformance.test.ts +14 -1
  120. package/server/service/testing/mode-conformance.ts +2 -0
  121. package/test/assistant-dock.test.ts +73 -0
  122. package/translations/en.json +25 -1
  123. package/translations/es.json +25 -1
  124. package/translations/ja.json +25 -1
  125. package/translations/ko.json +25 -1
  126. package/translations/ms.json +25 -1
  127. package/translations/zh.json +25 -1
@@ -13,6 +13,7 @@ const code = (file: string) => read(file).replace(/\/\*[\s\S]*?\*\//g, '').repla
13
13
  const dock = code('../client/components/assistant-dock.ts')
14
14
  /* Not comment-stripped: the chat has strings like 'image/*' that a comment regex would eat. */
15
15
  const chat = read('../client/components/assistant-chat.ts')
16
+ const transport = read('../client/utils/assistant-session-transport.ts')
16
17
 
17
18
  describe('no empty panel', () => {
18
19
  it('not configured, unreadable, no surface and a stuck anchor are each said', () => {
@@ -171,6 +172,20 @@ describe('what twin needed of the dock', () => {
171
172
  assert.match(dock, /this\.startCarried\(ask\)\.catch\(\(?\w*\)? => \{\s*notify\(\{ level: 'error'/)
172
173
  })
173
174
 
175
+ it('★ a request made on the screen is never dropped while an answer is written - it waits and is taken after', () => {
176
+ const busy = dock.slice(dock.indexOf('if (this.navigationState.busy) {', dock.indexOf('private async takeAsk')), dock.indexOf('if (this.navigationState.draft', dock.indexOf('private async takeAsk')))
177
+ assert.match(busy, /this\.takeWhenIdle\(\)\s*return/)
178
+ assert.doesNotMatch(busy, /takeAssistantAsk\(\)/)
179
+ })
180
+
181
+ it('★ unsent words are asked about before a new request takes the dock - never dropped without asking', () => {
182
+ assert.match(dock, /if \(this\.navigationState\.draft && !\(await this\.mayLeaveConversation\(\)\)\) \{\s*const waiting = takeAssistantAsk\(\)/)
183
+ })
184
+
185
+ it('a note is drawn without the line only the model reads', () => {
186
+ assert.match(chat, />\$\{noteForDisplay\(content\)\}<\/span/)
187
+ })
188
+
174
189
  it('★ and nothing is sent into the previous conversation after it - the request depended on the context that failed', () => {
175
190
  assert.match(dock, /this\.startCarried\(ask\)\.catch\([\s\S]*?return undefined\s*\}\)[\s\S]{0,200}?if \(!id\) return\n/)
176
191
  })
@@ -203,3 +218,61 @@ describe('closing and opening the dock again (design/ai/shared-dock.md §2-1, §
203
218
  assert.match(opening, /if \(this\.hasUpdated && this\.sessionId\) \{\s*this\.loadHistory\(\)\s*this\._startPresence\(\)\s*this\._startMessageSubscription\(\)/)
204
219
  })
205
220
  })
221
+
222
+ /*
223
+ * A screen request (「AI와 작업」) - design/ai/shared-dock.md §2-11-1, the user (2026-10-24): 「"AI와 작업" 기능이 unstable
224
+ * 하다. 작동 방식을 신뢰할 수 있도록 새로운 세션을 여는지, 기존 세션을 활용하는지 등등을 명확하게 하라.」 One test per rule.
225
+ */
226
+ describe('a screen request', () => {
227
+ const take = dock.slice(dock.indexOf('private async takeScreenRequest()'), dock.indexOf('\n }\n', dock.indexOf('private async takeScreenRequest()')))
228
+ const send = chat.slice(chat.indexOf('async sendScreenRequest('), chat.indexOf('\n }\n', chat.indexOf('async sendScreenRequest(')))
229
+
230
+ it('goes its own way - a request carrying a selection is a screen request', () => {
231
+ assert.match(dock, /if \(peekAssistantAsk\(\)\?\.selection\) return this\.takeScreenRequest\(\)/)
232
+ })
233
+
234
+ it('★ 1. to this screen\'s conversation - never a new one; another screen\'s conversation open comes back here', () => {
235
+ assert.doesNotMatch(take, /newConversation|startCarried|createAISession|controller\.reset|conversationView\+\+/)
236
+ assert.match(take, /if \(this\.scopeKey\(here\) !== this\.openedFor[^\n]*\) \{\s*(?:\/\*[^*]*\*\/\s*)?this\.keepDraft\(\)\s*this\.surface = here\s*await this\.open\(\)/)
237
+ assert.match(take, /this\.showingHistory = false/)
238
+ /* Someone else's open conversation the dock showed by default is not this person's - their own is started (draft along). */
239
+ assert.match(take, /if \(this\.sessions\.find\(one => one\.id === this\.sessionId\)\?\.participant === false\) await this\.goToOwnConversation\(\)/)
240
+ /* ...and that is their own most recent one here, a new one only when they have none. */
241
+ assert.match(dock, /const own = this\.sessions\.find\(one => one\.participant !== false && one\.id !== this\.sessionId\)/)
242
+ assert.match(dock, /if \(own\) \{\s*if \(this\.controller\.select\(own\.id\)\) this\.conversationView\+\+\s*\} else \{\s*await this\.controller\.reset\(\)/)
243
+ assert.match(transport, /participant\}\}/)
244
+ /* No conversation yet: the chat makes this screen's one on sending, through the controller - never a second. */
245
+ assert.match(send, /if \(!this\.sessionId && this\.prepareSession\) \{\s*await this\.prepareSession\(/)
246
+ })
247
+
248
+ it('★ 2. the selection is noted for that turn, before the request', () => {
249
+ assert.match(take, /chat\.sendScreenRequest\(request, selectionNote\(ask\.selection!, t\)\)/)
250
+ const noted = send.indexOf('APPEND_SESSION_NOTE_MUTATION')
251
+ assert.ok(noted > 0 && noted < send.indexOf('await this.send()'))
252
+ })
253
+
254
+ it('★ 3. sent, always - the request goes out, never as a draft', () => {
255
+ assert.match(send, /this\.input = text\s*await this\.send\(\)/)
256
+ assert.doesNotMatch(take, /asking|draft:/)
257
+ assert.match(take, /ask\.ask\?\.trim\(\) \|\| t\('screen-request-default'/)
258
+ })
259
+
260
+ it('★ 4. what the person was writing is set aside and put back', () => {
261
+ assert.match(send, /const kept = this\.takeDraft\(\)/)
262
+ assert.match(send, /finally \{[\s\S]*if \(kept && !this\.input\.trim\(\) && !this\.attachments\.length\) this\.restoreDraft\(kept\)/)
263
+ assert.match(send, /if \(this\.input\.trim\(\) === text\.trim\(\)\) this\.input = ''/)
264
+ })
265
+
266
+ it('★ 5. not sent: said, and the screen is told', () => {
267
+ assert.match(take, /const fail = \(reason: string\) => \{\s*notify\(\{ level: 'error', message: reason \}\)\s*settleAssistantAsk\(ask, \{ sent: false, reason \}\)/)
268
+ assert.match(take, /if \(!outcome\?\.sent\) return fail\(/)
269
+ assert.match(take, /settleAssistantAsk\(ask, \{ sent: true \}\)/)
270
+ })
271
+
272
+ it('★ 6. an answer being written: said once, and the request goes right after it', () => {
273
+ const busy = take.slice(take.indexOf('if (this.navigationState.busy)'), take.indexOf('const here'))
274
+ assert.match(busy, /notify\(\{ level: 'info', message: t\('screen-request-waits'/)
275
+ assert.match(busy, /this\.takeWhenIdle\(\)\s*return/)
276
+ assert.doesNotMatch(busy, /takeAssistantAsk\(\)/)
277
+ })
278
+ })
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} brought you into the conversation \"{name}\".",
425
425
  "ai-assistant.text.invite-body": "{who} brought you into a conversation.",
426
426
  "ai-assistant.text.board-invite-title": "Board collaboration invite",
427
- "ai-assistant.text.board-invite-body": "{who} invited you to collaborate on a board."
427
+ "ai-assistant.text.board-invite-body": "{who} invited you to collaborate on a board.",
428
+ "ai-assistant.people.title": "People",
429
+ "ai-assistant.people.name": "Name",
430
+ "ai-assistant.people.department": "Department",
431
+ "ai-assistant.people.position": "Position",
432
+ "ai-assistant.people.responsibility": "Responsibility",
433
+ "ai-assistant.people.user": "User",
434
+ "ai-assistant.people.invite-one": "Invite {name} to this conversation",
435
+ "ai-assistant.people.invite-pick": "{count} people named {name} - pick whom to invite",
436
+ "ai-assistant.people.invited": "{names} joined this conversation and was told.",
437
+ "ai-assistant.dock.selection-note": "Selected {count} · {title}",
438
+ "ai-assistant.dock.selection-more": "and {count} more",
439
+ "ai-assistant.dock.screen-request-waits": "An answer is being written - your request goes right after it.",
440
+ "ai-assistant.dock.screen-request-not-ready": "The conversation is not ready yet. Try again in a moment.",
441
+ "ai-assistant.dock.screen-request-default": "Read the selected records and suggest what can be done with them now.",
442
+ "ai-assistant.dock.screen-request-failed": "The request was not sent. Try again.",
443
+ "ai-assistant.text.screen-request-busy": "an answer is still being written.",
444
+ "ai-assistant.text.screen-request-no-session": "this screen has no conversation to send to.",
445
+ "ai-assistant.selection.count": "{n} selected",
446
+ "ai-assistant.selection.request": "Describe what to do with these records",
447
+ "ai-assistant.selection.work-with-ai": "Work with AI",
448
+ "ai-assistant.selection.region": "Work with selection",
449
+ "ai-assistant.selection.pick-rows": "Select rows to work on with AI.",
450
+ "ai-assistant.selection.save-first": "Save or cancel pending edits before working with the selected rows.",
451
+ "ai-assistant.selection.ask": "Read the {n} selected records from {title} and suggest what can be done with them now."
428
452
  }
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} te invitó a la conversación \"{name}\".",
425
425
  "ai-assistant.text.invite-body": "{who} te invitó a una conversación.",
426
426
  "ai-assistant.text.board-invite-title": "Invitación a colaborar en un tablero",
427
- "ai-assistant.text.board-invite-body": "{who} te invitó a colaborar en un tablero."
427
+ "ai-assistant.text.board-invite-body": "{who} te invitó a colaborar en un tablero.",
428
+ "ai-assistant.people.title": "Personas",
429
+ "ai-assistant.people.name": "Nombre",
430
+ "ai-assistant.people.department": "Departamento",
431
+ "ai-assistant.people.position": "Cargo",
432
+ "ai-assistant.people.responsibility": "Responsabilidad",
433
+ "ai-assistant.people.user": "Usuario",
434
+ "ai-assistant.people.invite-one": "Invitar a {name} a esta conversación",
435
+ "ai-assistant.people.invite-pick": "Hay {count} personas llamadas {name}: elige a quién invitar",
436
+ "ai-assistant.people.invited": "{names} se unió a esta conversación y recibió un aviso.",
437
+ "ai-assistant.dock.selection-note": "{count} seleccionados · {title}",
438
+ "ai-assistant.dock.selection-more": "y {count} más",
439
+ "ai-assistant.dock.screen-request-waits": "Se está escribiendo una respuesta: tu solicitud se envía justo después.",
440
+ "ai-assistant.dock.screen-request-not-ready": "La conversación aún no está lista. Inténtalo de nuevo en un momento.",
441
+ "ai-assistant.dock.screen-request-default": "Lee los registros seleccionados y sugiere qué se puede hacer ahora.",
442
+ "ai-assistant.dock.screen-request-failed": "La solicitud no se envió. Inténtalo de nuevo.",
443
+ "ai-assistant.text.screen-request-busy": "todavía se está escribiendo una respuesta.",
444
+ "ai-assistant.text.screen-request-no-session": "esta pantalla no tiene una conversación a la que enviar.",
445
+ "ai-assistant.selection.count": "{n} seleccionados",
446
+ "ai-assistant.selection.request": "Describe qué hacer con estos registros",
447
+ "ai-assistant.selection.work-with-ai": "Trabajar con IA",
448
+ "ai-assistant.selection.region": "Trabajar con la selección",
449
+ "ai-assistant.selection.pick-rows": "Selecciona primero las filas con las que trabajar con la IA.",
450
+ "ai-assistant.selection.save-first": "Guarda o cancela las ediciones pendientes antes de trabajar con las filas seleccionadas.",
451
+ "ai-assistant.selection.ask": "Lee los {n} registros seleccionados de {title} y sugiere qué se puede hacer con ellos ahora."
428
452
  }
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} さんが会話「{name}」に招待しました。",
425
425
  "ai-assistant.text.invite-body": "{who} さんが会話に招待しました。",
426
426
  "ai-assistant.text.board-invite-title": "ボード共同作業への招待",
427
- "ai-assistant.text.board-invite-body": "{who} さんがボードの共同作業に招待しました。"
427
+ "ai-assistant.text.board-invite-body": "{who} さんがボードの共同作業に招待しました。",
428
+ "ai-assistant.people.title": "メンバー",
429
+ "ai-assistant.people.name": "氏名",
430
+ "ai-assistant.people.department": "部署",
431
+ "ai-assistant.people.position": "役職",
432
+ "ai-assistant.people.responsibility": "担当",
433
+ "ai-assistant.people.user": "ユーザー",
434
+ "ai-assistant.people.invite-one": "{name} さんをこの会話に招待",
435
+ "ai-assistant.people.invite-pick": "{name} さんが {count} 人います — 招待する人を選んでください",
436
+ "ai-assistant.people.invited": "{names} さんがこの会話に参加し、通知を受けました。",
437
+ "ai-assistant.dock.selection-note": "選択 {count}件 · {title}",
438
+ "ai-assistant.dock.selection-more": "ほか {count}件",
439
+ "ai-assistant.dock.screen-request-waits": "回答を作成中です — 終わり次第リクエストを送ります。",
440
+ "ai-assistant.dock.screen-request-not-ready": "会話の準備がまだできていません。少し後でもう一度お試しください。",
441
+ "ai-assistant.dock.screen-request-default": "選択した記録を読んで、今できることをまとめて。",
442
+ "ai-assistant.dock.screen-request-failed": "リクエストを送れませんでした。もう一度お試しください。",
443
+ "ai-assistant.text.screen-request-busy": "まだ回答を作成中です。",
444
+ "ai-assistant.text.screen-request-no-session": "この画面には送信先の会話がありません。",
445
+ "ai-assistant.selection.count": "{n}件選択",
446
+ "ai-assistant.selection.request": "選択した項目にすることを入力してください",
447
+ "ai-assistant.selection.work-with-ai": "AIと作業",
448
+ "ai-assistant.selection.region": "選択項目の作業",
449
+ "ai-assistant.selection.pick-rows": "AIと作業する行を先に選択してください。",
450
+ "ai-assistant.selection.save-first": "編集中の内容を保存または取り消してから、選択した行で作業してください。",
451
+ "ai-assistant.selection.ask": "{title}で選択した{n}件を読んで、今できることをすぐ提案して。"
428
452
  }
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} 님이 \"{name}\" 대화에 초대했습니다.",
425
425
  "ai-assistant.text.invite-body": "{who} 님이 대화에 초대했습니다.",
426
426
  "ai-assistant.text.board-invite-title": "보드 협업 초대",
427
- "ai-assistant.text.board-invite-body": "{who} 님이 보드 협업에 초대했습니다."
427
+ "ai-assistant.text.board-invite-body": "{who} 님이 보드 협업에 초대했습니다.",
428
+ "ai-assistant.people.title": "구성원",
429
+ "ai-assistant.people.name": "이름",
430
+ "ai-assistant.people.department": "부서",
431
+ "ai-assistant.people.position": "직책",
432
+ "ai-assistant.people.responsibility": "담당",
433
+ "ai-assistant.people.user": "사용자",
434
+ "ai-assistant.people.invite-one": "{name} 님을 이 대화에 초대",
435
+ "ai-assistant.people.invite-pick": "{name} 님이 {count}명입니다 — 초대할 사람을 고르세요",
436
+ "ai-assistant.people.invited": "{names} 님이 이 대화에 들어왔고 알림을 받았습니다.",
437
+ "ai-assistant.dock.selection-note": "선택 {count}건 · {title}",
438
+ "ai-assistant.dock.selection-more": "외 {count}건",
439
+ "ai-assistant.dock.screen-request-waits": "답을 쓰는 중입니다 — 끝나면 바로 요청을 보냅니다.",
440
+ "ai-assistant.dock.screen-request-not-ready": "대화가 아직 준비되지 않았습니다. 잠시 뒤 다시 눌러 주세요.",
441
+ "ai-assistant.dock.screen-request-default": "선택한 기록을 읽고 지금 할 수 있는 일을 정리해 줘.",
442
+ "ai-assistant.dock.screen-request-failed": "요청을 보내지 못했습니다. 다시 눌러 주세요.",
443
+ "ai-assistant.text.screen-request-busy": "아직 답을 쓰는 중입니다.",
444
+ "ai-assistant.text.screen-request-no-session": "이 화면에는 보낼 대화가 없습니다.",
445
+ "ai-assistant.selection.count": "{n}건 선택",
446
+ "ai-assistant.selection.request": "선택한 항목에 할 일을 적으세요",
447
+ "ai-assistant.selection.work-with-ai": "AI와 작업",
448
+ "ai-assistant.selection.region": "선택 항목 작업",
449
+ "ai-assistant.selection.pick-rows": "AI와 함께 작업할 행을 먼저 선택하세요.",
450
+ "ai-assistant.selection.save-first": "편집 중인 내용을 먼저 저장하거나 취소한 뒤 선택한 행으로 작업하세요.",
451
+ "ai-assistant.selection.ask": "{title}에서 선택한 {n}건을 읽고 지금 할 수 있는 일을 바로 제안해 줘."
428
452
  }
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} menjemput anda ke perbualan \"{name}\".",
425
425
  "ai-assistant.text.invite-body": "{who} menjemput anda ke sebuah perbualan.",
426
426
  "ai-assistant.text.board-invite-title": "Jemputan kerjasama papan",
427
- "ai-assistant.text.board-invite-body": "{who} menjemput anda bekerjasama pada papan."
427
+ "ai-assistant.text.board-invite-body": "{who} menjemput anda bekerjasama pada papan.",
428
+ "ai-assistant.people.title": "Ahli",
429
+ "ai-assistant.people.name": "Nama",
430
+ "ai-assistant.people.department": "Jabatan",
431
+ "ai-assistant.people.position": "Jawatan",
432
+ "ai-assistant.people.responsibility": "Tanggungjawab",
433
+ "ai-assistant.people.user": "Pengguna",
434
+ "ai-assistant.people.invite-one": "Jemput {name} ke perbualan ini",
435
+ "ai-assistant.people.invite-pick": "{count} orang bernama {name} - pilih siapa yang hendak dijemput",
436
+ "ai-assistant.people.invited": "{names} telah menyertai perbualan ini dan dimaklumkan.",
437
+ "ai-assistant.dock.selection-note": "Dipilih {count} · {title}",
438
+ "ai-assistant.dock.selection-more": "dan {count} lagi",
439
+ "ai-assistant.dock.screen-request-waits": "Jawapan sedang ditulis - permintaan anda dihantar sejurus selepas itu.",
440
+ "ai-assistant.dock.screen-request-not-ready": "Perbualan belum sedia. Cuba lagi sebentar lagi.",
441
+ "ai-assistant.dock.screen-request-default": "Baca rekod yang dipilih dan cadangkan apa yang boleh dibuat sekarang.",
442
+ "ai-assistant.dock.screen-request-failed": "Permintaan tidak dihantar. Cuba lagi.",
443
+ "ai-assistant.text.screen-request-busy": "jawapan masih sedang ditulis.",
444
+ "ai-assistant.text.screen-request-no-session": "skrin ini tiada perbualan untuk dihantar.",
445
+ "ai-assistant.selection.count": "{n} dipilih",
446
+ "ai-assistant.selection.request": "Tulis apa yang perlu dibuat dengan rekod ini",
447
+ "ai-assistant.selection.work-with-ai": "Bekerja dengan AI",
448
+ "ai-assistant.selection.region": "Kerja dengan pilihan",
449
+ "ai-assistant.selection.pick-rows": "Pilih baris untuk diusahakan bersama AI dahulu.",
450
+ "ai-assistant.selection.save-first": "Simpan atau batalkan suntingan yang belum disimpan sebelum bekerja dengan baris yang dipilih.",
451
+ "ai-assistant.selection.ask": "Baca {n} rekod yang dipilih daripada {title} dan cadangkan apa yang boleh dibuat sekarang."
428
452
  }
@@ -424,5 +424,29 @@
424
424
  "ai-assistant.text.invite-body-named": "{who} 邀请你加入对话“{name}”。",
425
425
  "ai-assistant.text.invite-body": "{who} 邀请你加入对话。",
426
426
  "ai-assistant.text.board-invite-title": "看板协作邀请",
427
- "ai-assistant.text.board-invite-body": "{who} 邀请你协作编辑看板。"
427
+ "ai-assistant.text.board-invite-body": "{who} 邀请你协作编辑看板。",
428
+ "ai-assistant.people.title": "成员",
429
+ "ai-assistant.people.name": "姓名",
430
+ "ai-assistant.people.department": "部门",
431
+ "ai-assistant.people.position": "职位",
432
+ "ai-assistant.people.responsibility": "职责",
433
+ "ai-assistant.people.user": "用户",
434
+ "ai-assistant.people.invite-one": "邀请 {name} 加入此对话",
435
+ "ai-assistant.people.invite-pick": "有 {count} 位 {name} — 请选择要邀请的人",
436
+ "ai-assistant.people.invited": "{names} 已加入此对话并收到通知。",
437
+ "ai-assistant.dock.selection-note": "已选 {count} 条 · {title}",
438
+ "ai-assistant.dock.selection-more": "等另外 {count} 条",
439
+ "ai-assistant.dock.screen-request-waits": "正在生成回答 — 完成后立即发送你的请求。",
440
+ "ai-assistant.dock.screen-request-not-ready": "对话尚未就绪,请稍后再试。",
441
+ "ai-assistant.dock.screen-request-default": "读取所选记录,并整理现在可以做的事。",
442
+ "ai-assistant.dock.screen-request-failed": "请求未发送,请重试。",
443
+ "ai-assistant.text.screen-request-busy": "回答仍在生成中。",
444
+ "ai-assistant.text.screen-request-no-session": "此页面没有可发送的对话。",
445
+ "ai-assistant.selection.count": "已选择 {n} 条",
446
+ "ai-assistant.selection.request": "请写下要对所选记录做什么",
447
+ "ai-assistant.selection.work-with-ai": "与 AI 协作",
448
+ "ai-assistant.selection.region": "所选记录操作",
449
+ "ai-assistant.selection.pick-rows": "请先选择要与 AI 一起处理的行。",
450
+ "ai-assistant.selection.save-first": "请先保存或取消正在编辑的内容,再处理所选行。",
451
+ "ai-assistant.selection.ask": "读取在{title}中选择的{n}条记录,并立即提出现在可以做的事。"
428
452
  }