@yadsh/dsh-qa-surface 0.13.0 → 0.14.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 (336) hide show
  1. package/README.md +148 -22
  2. package/compatibility.json +7 -3
  3. package/lib/access/capability-catalog.js +22 -6
  4. package/lib/access/capability-catalog.js.map +1 -1
  5. package/lib/access/model.js +36 -2
  6. package/lib/access/model.js.map +1 -1
  7. package/lib/access/service.js +19 -4
  8. package/lib/access/service.js.map +1 -1
  9. package/lib/account-remotes.js +4 -0
  10. package/lib/account-remotes.js.map +1 -1
  11. package/lib/accounts/database.js +49 -9
  12. package/lib/accounts/database.js.map +1 -1
  13. package/lib/accounts/errors.js.map +1 -1
  14. package/lib/accounts/file.js.map +1 -1
  15. package/lib/accounts/store.js +53 -8
  16. package/lib/accounts/store.js.map +1 -1
  17. package/lib/admin/permissions.js +6 -0
  18. package/lib/admin/permissions.js.map +1 -1
  19. package/lib/admin/quality-store.js +95 -19
  20. package/lib/admin/quality-store.js.map +1 -1
  21. package/lib/admin/service.js +178 -0
  22. package/lib/admin/service.js.map +1 -1
  23. package/lib/cli.js +24 -4
  24. package/lib/cli.js.map +1 -1
  25. package/lib/client/QaAccountsController.js +52 -5
  26. package/lib/client/QaAccountsController.js.map +1 -1
  27. package/lib/client/QaConfigController.js.map +1 -1
  28. package/lib/client/QaSessionController.js +626 -63
  29. package/lib/client/QaSessionController.js.map +1 -1
  30. package/lib/client/QaSurface.js +279 -43
  31. package/lib/client/QaSurface.js.map +1 -1
  32. package/lib/client/QaSurfaceGuard.js +2 -2
  33. package/lib/client/QaSurfaceGuard.js.map +1 -1
  34. package/lib/client/QaTranscriptAdapter.js +4 -2
  35. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  36. package/lib/client/admin/QaAdmin.js +59 -34
  37. package/lib/client/admin/QaAdmin.js.map +1 -1
  38. package/lib/client/admin/pages/Conversations.js +12 -12
  39. package/lib/client/admin/pages/Conversations.js.map +1 -1
  40. package/lib/client/admin/pages/ExpertMemory.js +210 -0
  41. package/lib/client/admin/pages/ExpertMemory.js.map +1 -0
  42. package/lib/client/admin/pages/Overview.js +4 -4
  43. package/lib/client/admin/pages/Overview.js.map +1 -1
  44. package/lib/client/admin/pages/Quality.js +5 -5
  45. package/lib/client/admin/pages/Quality.js.map +1 -1
  46. package/lib/client/admin/pages/Review.js +5 -5
  47. package/lib/client/admin/pages/Review.js.map +1 -1
  48. package/lib/client/admin/pages/SkillFiles.js +3 -3
  49. package/lib/client/admin/pages/SkillFiles.js.map +1 -1
  50. package/lib/client/admin/pages/Users.js +12 -12
  51. package/lib/client/admin/pages/Users.js.map +1 -1
  52. package/lib/client/admin/routes.js +4 -0
  53. package/lib/client/admin/routes.js.map +1 -1
  54. package/lib/client/admin/shared.js +15 -6
  55. package/lib/client/admin/shared.js.map +1 -1
  56. package/lib/client/admin/styles.js +3 -0
  57. package/lib/client/admin/styles.js.map +1 -1
  58. package/lib/client/attestation.js +11 -2
  59. package/lib/client/attestation.js.map +1 -1
  60. package/lib/client/audit/QaAuditDialog.js +2 -2
  61. package/lib/client/audit/QaAuditDialog.js.map +1 -1
  62. package/lib/client/audit/QaAuditRowBadge.js +1 -1
  63. package/lib/client/audit/QaAuditRowBadge.js.map +1 -1
  64. package/lib/client/components/Markdown.js +7 -2
  65. package/lib/client/components/Markdown.js.map +1 -1
  66. package/lib/client/components/QaAgentsDrawer.js +7 -5
  67. package/lib/client/components/QaAgentsDrawer.js.map +1 -1
  68. package/lib/client/components/QaApproval.js +2 -2
  69. package/lib/client/components/QaApproval.js.map +1 -1
  70. package/lib/client/components/QaAuthGate.js +6 -6
  71. package/lib/client/components/QaAuthGate.js.map +1 -1
  72. package/lib/client/components/QaChangelog.js +64 -0
  73. package/lib/client/components/QaChangelog.js.map +1 -1
  74. package/lib/client/components/QaComposer.js +9 -6
  75. package/lib/client/components/QaComposer.js.map +1 -1
  76. package/lib/client/components/QaFileAttachment.js +1 -1
  77. package/lib/client/components/QaFileAttachment.js.map +1 -1
  78. package/lib/client/components/QaFilesPanel.js +7 -7
  79. package/lib/client/components/QaFilesPanel.js.map +1 -1
  80. package/lib/client/components/QaHeader.js +4 -4
  81. package/lib/client/components/QaHeader.js.map +1 -1
  82. package/lib/client/components/QaMessage.js +12 -12
  83. package/lib/client/components/QaMessage.js.map +1 -1
  84. package/lib/client/components/QaModal.js +11 -2
  85. package/lib/client/components/QaModal.js.map +1 -1
  86. package/lib/client/components/QaQuestions.js +4 -4
  87. package/lib/client/components/QaQuestions.js.map +1 -1
  88. package/lib/client/components/QaQueueDock.js +137 -0
  89. package/lib/client/components/QaQueueDock.js.map +1 -0
  90. package/lib/client/components/QaRequestQueue.js +22 -0
  91. package/lib/client/components/QaRequestQueue.js.map +1 -0
  92. package/lib/client/components/QaRightRail.js +2 -2
  93. package/lib/client/components/QaRightRail.js.map +1 -1
  94. package/lib/client/components/QaSidebar.js +66 -6
  95. package/lib/client/components/QaSidebar.js.map +1 -1
  96. package/lib/client/components/QaSourcesPanel.js +10 -8
  97. package/lib/client/components/QaSourcesPanel.js.map +1 -1
  98. package/lib/client/components/QaThemeSwitcher.js +19 -0
  99. package/lib/client/components/QaThemeSwitcher.js.map +1 -0
  100. package/lib/client/components/QaTurnNotice.js +40 -0
  101. package/lib/client/components/QaTurnNotice.js.map +1 -0
  102. package/lib/client/components/QaTurnRail.js +3 -3
  103. package/lib/client/components/QaTurnRail.js.map +1 -1
  104. package/lib/client/components/QaWelcomeNotice.js +2 -6
  105. package/lib/client/components/QaWelcomeNotice.js.map +1 -1
  106. package/lib/client/components/QaWidthHandle.js +2 -2
  107. package/lib/client/components/QaWidthHandle.js.map +1 -1
  108. package/lib/client/components/QaWorkGroup.js +5 -5
  109. package/lib/client/components/QaWorkGroup.js.map +1 -1
  110. package/lib/client/components/QaWorkspaceBrowser.js +10 -10
  111. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -1
  112. package/lib/client/components/VariantSwitcher.js +1 -1
  113. package/lib/client/components/VariantSwitcher.js.map +1 -1
  114. package/lib/client/failure-copy.js +26 -8
  115. package/lib/client/failure-copy.js.map +1 -1
  116. package/lib/client/focus-ring.js +193 -0
  117. package/lib/client/focus-ring.js.map +1 -0
  118. package/lib/client/index.js +40 -20
  119. package/lib/client/index.js.map +1 -1
  120. package/lib/client/lineage.js +3 -16
  121. package/lib/client/lineage.js.map +1 -1
  122. package/lib/client/markdown/CodeBlock.js +2 -2
  123. package/lib/client/markdown/CodeBlock.js.map +1 -1
  124. package/lib/client/markdown/blocks.js +118 -31
  125. package/lib/client/markdown/blocks.js.map +1 -1
  126. package/lib/client/markdown/math.js +1 -1
  127. package/lib/client/markdown/math.js.map +1 -1
  128. package/lib/client/markdown/render.js +32 -16
  129. package/lib/client/markdown/render.js.map +1 -1
  130. package/lib/client/markdown/source-chip.js +3 -3
  131. package/lib/client/markdown/source-chip.js.map +1 -1
  132. package/lib/client/notifications/notification-dispatcher.js +90 -0
  133. package/lib/client/notifications/notification-dispatcher.js.map +1 -0
  134. package/lib/client/notifications/preferences.js +61 -0
  135. package/lib/client/notifications/preferences.js.map +1 -0
  136. package/lib/client/notifications/turn-completion-source.js +82 -0
  137. package/lib/client/notifications/turn-completion-source.js.map +1 -0
  138. package/lib/client/notifications/use-turn-notifications.js +108 -0
  139. package/lib/client/notifications/use-turn-notifications.js.map +1 -0
  140. package/lib/client/panels/PanelHost.js +5 -5
  141. package/lib/client/panels/PanelHost.js.map +1 -1
  142. package/lib/client/panels/PanelLauncher.js +2 -2
  143. package/lib/client/panels/PanelLauncher.js.map +1 -1
  144. package/lib/client/project-session-state.js +156 -4
  145. package/lib/client/project-session-state.js.map +1 -1
  146. package/lib/client/role/RoleSelector.js +9 -4
  147. package/lib/client/role/RoleSelector.js.map +1 -1
  148. package/lib/client/settings/card.js +58 -17
  149. package/lib/client/settings/card.js.map +1 -1
  150. package/lib/client/settings/fields.js +11 -10
  151. package/lib/client/settings/fields.js.map +1 -1
  152. package/lib/client/settings/format.js +0 -9
  153. package/lib/client/settings/format.js.map +1 -1
  154. package/lib/client/settings/sections/access.js +5 -5
  155. package/lib/client/settings/sections/access.js.map +1 -1
  156. package/lib/client/settings/sections/accounts.js +10 -10
  157. package/lib/client/settings/sections/accounts.js.map +1 -1
  158. package/lib/client/settings/sections/attachments.js +6 -6
  159. package/lib/client/settings/sections/attachments.js.map +1 -1
  160. package/lib/client/settings/sections/branding.js +7 -7
  161. package/lib/client/settings/sections/branding.js.map +1 -1
  162. package/lib/client/settings/sections/common.js +4 -2
  163. package/lib/client/settings/sections/common.js.map +1 -1
  164. package/lib/client/settings/sections/docs.js +4 -3
  165. package/lib/client/settings/sections/docs.js.map +1 -1
  166. package/lib/client/settings/sections/embedding.js +2 -2
  167. package/lib/client/settings/sections/embedding.js.map +1 -1
  168. package/lib/client/settings/sections/interface.js +12 -12
  169. package/lib/client/settings/sections/interface.js.map +1 -1
  170. package/lib/client/settings/sections/lockdown.js +9 -9
  171. package/lib/client/settings/sections/lockdown.js.map +1 -1
  172. package/lib/client/settings/sections/notes.js +12 -12
  173. package/lib/client/settings/sections/notes.js.map +1 -1
  174. package/lib/client/settings/sections/session.js +15 -12
  175. package/lib/client/settings/sections/session.js.map +1 -1
  176. package/lib/client/settings/sections/slash.js +9 -9
  177. package/lib/client/settings/sections/slash.js.map +1 -1
  178. package/lib/client/settings/sections/sources.js +26 -26
  179. package/lib/client/settings/sections/sources.js.map +1 -1
  180. package/lib/client/settings/sections/status.js +2 -2
  181. package/lib/client/settings/sections/status.js.map +1 -1
  182. package/lib/client/settings/styles.js +15 -9
  183. package/lib/client/settings/styles.js.map +1 -1
  184. package/lib/client/slash/SlashPalette.js +4 -4
  185. package/lib/client/slash/SlashPalette.js.map +1 -1
  186. package/lib/client/styles.js +133 -83
  187. package/lib/client/styles.js.map +1 -1
  188. package/lib/client/theme-preference.js +162 -0
  189. package/lib/client/theme-preference.js.map +1 -0
  190. package/lib/client/types.js +8 -0
  191. package/lib/client/types.js.map +1 -1
  192. package/lib/client/use-session-ui-state.js +7 -5
  193. package/lib/client/use-session-ui-state.js.map +1 -1
  194. package/lib/client/user-settings/GeneralSettingsPage.js +6 -6
  195. package/lib/client/user-settings/GeneralSettingsPage.js.map +1 -1
  196. package/lib/client/user-settings/IntegrationTokensPage.js +6 -6
  197. package/lib/client/user-settings/IntegrationTokensPage.js.map +1 -1
  198. package/lib/client/user-settings/NotificationSettingsPage.js +107 -0
  199. package/lib/client/user-settings/NotificationSettingsPage.js.map +1 -0
  200. package/lib/client/user-settings/PasswordSettingsPage.js +1 -1
  201. package/lib/client/user-settings/PasswordSettingsPage.js.map +1 -1
  202. package/lib/client/user-settings/ProfileSettingsPage.js +2 -2
  203. package/lib/client/user-settings/ProfileSettingsPage.js.map +1 -1
  204. package/lib/client/user-settings/SkillCatalog.js +3 -3
  205. package/lib/client/user-settings/SkillCatalog.js.map +1 -1
  206. package/lib/client/user-settings/SkillEditor.js +26 -8
  207. package/lib/client/user-settings/SkillEditor.js.map +1 -1
  208. package/lib/client/user-settings/SkillToolPicker.js +3 -3
  209. package/lib/client/user-settings/SkillToolPicker.js.map +1 -1
  210. package/lib/client/user-settings/SkillsSettingsPage.js +1 -1
  211. package/lib/client/user-settings/SkillsSettingsPage.js.map +1 -1
  212. package/lib/client/user-settings/StartersSettingsPage.js +6 -6
  213. package/lib/client/user-settings/StartersSettingsPage.js.map +1 -1
  214. package/lib/client/user-settings/UserSettingsDialog.js +7 -2
  215. package/lib/client/user-settings/UserSettingsDialog.js.map +1 -1
  216. package/lib/client/user-settings/copy.js +2 -0
  217. package/lib/client/user-settings/copy.js.map +1 -1
  218. package/lib/client/user-settings/draft.js +4 -1
  219. package/lib/client/user-settings/draft.js.map +1 -1
  220. package/lib/client/user-settings/fields.js +5 -5
  221. package/lib/client/user-settings/fields.js.map +1 -1
  222. package/lib/client.js +7228 -4002
  223. package/lib/client.js.map +1 -1
  224. package/lib/config-resolvers/defaults.js +7 -0
  225. package/lib/config-resolvers/defaults.js.map +1 -1
  226. package/lib/config-resolvers/lockdown.js +7 -0
  227. package/lib/config-resolvers/lockdown.js.map +1 -1
  228. package/lib/config-resolvers/notifications.js +15 -0
  229. package/lib/config-resolvers/notifications.js.map +1 -0
  230. package/lib/config-resolvers/session.js +11 -1
  231. package/lib/config-resolvers/session.js.map +1 -1
  232. package/lib/config.js +67 -18
  233. package/lib/config.js.map +1 -1
  234. package/lib/enforcement/tool-grants.js +6 -6
  235. package/lib/enforcement/tool-grants.js.map +1 -1
  236. package/lib/index.js +145 -30
  237. package/lib/index.js.map +1 -1
  238. package/lib/integration/answer.js +74 -8
  239. package/lib/integration/answer.js.map +1 -1
  240. package/lib/integration/expert-memory.js +39 -0
  241. package/lib/integration/expert-memory.js.map +1 -0
  242. package/lib/integration/host-runner.js +26 -14
  243. package/lib/integration/host-runner.js.map +1 -1
  244. package/lib/notifications.js +66 -0
  245. package/lib/notifications.js.map +1 -0
  246. package/lib/personal-skills/errors.js.map +1 -1
  247. package/lib/personal-skills/service.js +81 -7
  248. package/lib/personal-skills/service.js.map +1 -1
  249. package/lib/prompt-notes.js +2 -10
  250. package/lib/prompt-notes.js.map +1 -1
  251. package/lib/qa-tools/docs-tools.js +1 -1
  252. package/lib/qa-tools/docs-tools.js.map +1 -1
  253. package/lib/qa-tools/lifecycle.js +6 -3
  254. package/lib/qa-tools/lifecycle.js.map +1 -1
  255. package/lib/request-queue.js +32 -0
  256. package/lib/request-queue.js.map +1 -0
  257. package/lib/resolve-config.js +2 -0
  258. package/lib/resolve-config.js.map +1 -1
  259. package/lib/secure-session.js +7 -2
  260. package/lib/secure-session.js.map +1 -1
  261. package/lib/shared/settings.js +19 -2
  262. package/lib/shared/settings.js.map +1 -1
  263. package/lib/turn-failure-log.js +67 -0
  264. package/lib/turn-failure-log.js.map +1 -0
  265. package/lib/typert.host.js +1398 -651
  266. package/lib/typert.remote-client.d.ts +15 -1
  267. package/lib/typert.remote-client.js +1315 -645
  268. package/lib/types/access/capability-catalog.d.ts +20 -4
  269. package/lib/types/access/model.d.ts +23 -0
  270. package/lib/types/access/service.d.ts +2 -3
  271. package/lib/types/account-remotes.d.ts +8 -1
  272. package/lib/types/accounts/database.d.ts +13 -3
  273. package/lib/types/accounts/errors.d.ts +9 -1
  274. package/lib/types/accounts/file.d.ts +12 -0
  275. package/lib/types/accounts/store.d.ts +30 -2
  276. package/lib/types/admin/quality-store.d.ts +33 -0
  277. package/lib/types/admin/service.d.ts +60 -1
  278. package/lib/types/client/QaAccountsController.d.ts +25 -2
  279. package/lib/types/client/QaConfigController.d.ts +2 -2
  280. package/lib/types/client/QaSessionController.d.ts +199 -6
  281. package/lib/types/client/QaSurface.d.ts +6 -1
  282. package/lib/types/client/admin/pages/ExpertMemory.d.ts +19 -0
  283. package/lib/types/client/admin/routes.d.ts +3 -1
  284. package/lib/types/client/admin/shared.d.ts +4 -0
  285. package/lib/types/client/components/Markdown.d.ts +8 -1
  286. package/lib/types/client/components/QaHeader.d.ts +3 -1
  287. package/lib/types/client/components/QaModal.d.ts +7 -0
  288. package/lib/types/client/components/QaQueueDock.d.ts +27 -0
  289. package/lib/types/client/components/QaRequestQueue.d.ts +20 -0
  290. package/lib/types/client/components/QaThemeSwitcher.d.ts +14 -0
  291. package/lib/types/client/components/QaTurnNotice.d.ts +55 -0
  292. package/lib/types/client/focus-ring.d.ts +65 -0
  293. package/lib/types/client/lineage.d.ts +3 -13
  294. package/lib/types/client/markdown/blocks.d.ts +30 -2
  295. package/lib/types/client/markdown/render.d.ts +4 -1
  296. package/lib/types/client/notifications/notification-dispatcher.d.ts +68 -0
  297. package/lib/types/client/notifications/preferences.d.ts +44 -0
  298. package/lib/types/client/notifications/turn-completion-source.d.ts +114 -0
  299. package/lib/types/client/notifications/use-turn-notifications.d.ts +51 -0
  300. package/lib/types/client/project-session-state.d.ts +35 -1
  301. package/lib/types/client/role/RoleSelector.d.ts +7 -1
  302. package/lib/types/client/settings/card.d.ts +36 -5
  303. package/lib/types/client/settings/fields.d.ts +24 -0
  304. package/lib/types/client/settings/format.d.ts +0 -5
  305. package/lib/types/client/settings/sections/common.d.ts +3 -1
  306. package/lib/types/client/settings/sections/session.d.ts +2 -1
  307. package/lib/types/client/settings/styles.d.ts +9 -4
  308. package/lib/types/client/settings-extensions/user-session.d.ts +1 -1
  309. package/lib/types/client/theme-preference.d.ts +69 -0
  310. package/lib/types/client/types.d.ts +25 -1
  311. package/lib/types/client/use-session-ui-state.d.ts +6 -4
  312. package/lib/types/client/user-settings/GeneralSettingsPage.d.ts +5 -5
  313. package/lib/types/client/user-settings/NotificationSettingsPage.d.ts +40 -0
  314. package/lib/types/client/user-settings/UserSettingsDialog.d.ts +12 -2
  315. package/lib/types/client/user-settings/draft.d.ts +4 -1
  316. package/lib/types/client/user-settings/fields.d.ts +7 -0
  317. package/lib/types/config-resolvers/notifications.d.ts +10 -0
  318. package/lib/types/config-resolvers/session.d.ts +6 -0
  319. package/lib/types/config.d.ts +20 -1
  320. package/lib/types/index.d.ts +53 -5
  321. package/lib/types/integration/answer.d.ts +27 -0
  322. package/lib/types/integration/expert-memory.d.ts +49 -0
  323. package/lib/types/notifications.d.ts +32 -0
  324. package/lib/types/personal-skills/errors.d.ts +1 -1
  325. package/lib/types/personal-skills/service.d.ts +6 -0
  326. package/lib/types/prompt-notes.d.ts +17 -4
  327. package/lib/types/request-queue.d.ts +32 -0
  328. package/lib/types/shared/settings.d.ts +19 -2
  329. package/lib/types/turn-failure-log.d.ts +18 -0
  330. package/lib/types/types.d.ts +180 -4
  331. package/package.json +64 -63
  332. package/scripts/attach-workspace-sessions.mjs +24 -5
  333. package/scripts/repair-session-events.mjs +25 -5
  334. package/lib/client/markdown/MermaidBlock.js +0 -80
  335. package/lib/client/markdown/MermaidBlock.js.map +0 -1
  336. package/lib/types/client/markdown/MermaidBlock.d.ts +0 -6
@@ -24,11 +24,67 @@ function record(value) {
24
24
  */
25
25
  export function answerAfter(events, afterSeq) {
26
26
  const ordered = [...events].sort((left, right) => left.seq - right.seq);
27
+ return projectTurn(ordered, (event) => event.seq > afterSeq);
28
+ }
29
+ /**
30
+ * Project the answer of the turn one request's own prompt opened.
31
+ *
32
+ * The harness stamps the prompt's rpc id onto the durable user row it claims,
33
+ * so the row is found by id rather than guessed from the newest human message:
34
+ * two questions in flight on one chat open two turns, and a selection by
35
+ * "latest" answers each caller with the other's turn. The turn that answers a
36
+ * request is the one its row was claimed into — `turn/start` opens a turn and
37
+ * the claimed rows follow it — so the answer is read out of that turn's
38
+ * assistant messages only, and its number travels with it for the citation.
39
+ *
40
+ * @param events - durable events, in any order.
41
+ * @param requestId - the rpc id the prompt was submitted with.
42
+ * @returns the answer of this request's turn, or `undefined` when the log
43
+ * holds no row for the request (an unflushed prompt, or a harness that does not
44
+ * echo the id), which leaves the choice of cursor to the caller.
45
+ */
46
+ export function answerForRequest(events, requestId) {
47
+ const ordered = [...events].sort((left, right) => left.seq - right.seq);
48
+ let promptSeq;
49
+ let turn;
50
+ for (const event of ordered) {
51
+ if (promptSeq !== undefined)
52
+ break;
53
+ if (event.type === "turn/start") {
54
+ const data = record(event.data);
55
+ if (typeof data?.turn === "number")
56
+ turn = data.turn;
57
+ }
58
+ else if (isPromptOf(event, requestId)) {
59
+ promptSeq = event.seq;
60
+ }
61
+ }
62
+ if (promptSeq === undefined)
63
+ return undefined;
64
+ const ownSeq = promptSeq;
65
+ if (turn === undefined) {
66
+ // A row with no `turn/start` before it: the answer is whatever this prompt
67
+ // and the next human one bracket — the window the turn would have been.
68
+ let next = Number.POSITIVE_INFINITY;
69
+ for (const event of ordered) {
70
+ if (event.seq > ownSeq && isHumanPrompt(event) && event.seq < next) {
71
+ next = event.seq;
72
+ }
73
+ }
74
+ const bounded = projectTurn(ordered, (event) => event.seq > ownSeq && event.seq < next);
75
+ return Object.freeze({ ...bounded, turn: null });
76
+ }
77
+ const numbered = turn;
78
+ const projected = projectTurn(ordered, (event) => event.seq > ownSeq && record(event.data)?.turn === numbered);
79
+ return Object.freeze({ ...projected, turn: numbered });
80
+ }
81
+ /** Project one turn's answer out of the assistant messages it committed. */
82
+ function projectTurn(ordered, belongs) {
27
83
  let answer = "";
28
84
  let seq = null;
29
85
  let lastWasInterrupted = false;
30
86
  for (const event of ordered) {
31
- if (event.type !== "assistant/message" || event.seq <= afterSeq)
87
+ if (event.type !== "assistant/message" || !belongs(event))
32
88
  continue;
33
89
  const data = record(event.data);
34
90
  const message = record(data?.message);
@@ -41,6 +97,22 @@ export function answerAfter(events, afterSeq) {
41
97
  }
42
98
  return Object.freeze({ answer, interrupted: lastWasInterrupted, seq });
43
99
  }
100
+ /** The producing source of one durable message row, when it has one. */
101
+ function sourceOf(event) {
102
+ return record(record(event.data)?.source);
103
+ }
104
+ /** Whether one row is a human prompt, as opposed to injected context. */
105
+ function isHumanPrompt(event) {
106
+ return event.type === "user/message" && sourceOf(event)?.kind === "user";
107
+ }
108
+ /**
109
+ * Whether one row is the prompt submitted under `requestId`. The harness copies
110
+ * the prompt's rpc id onto its source, which is what ties a durable row back to
111
+ * the caller that wrote it.
112
+ */
113
+ function isPromptOf(event, requestId) {
114
+ return isHumanPrompt(event) && sourceOf(event)?.rpcId === requestId;
115
+ }
44
116
  /**
45
117
  * Cut an answer down to the size the caller publishes.
46
118
  *
@@ -86,13 +158,7 @@ export function boundAnswer(answer, maxCharacters) {
86
158
  export function lastPromptSeq(events) {
87
159
  let seq = 0;
88
160
  for (const event of events) {
89
- if (event.type !== "user/message")
90
- continue;
91
- const data = record(event.data);
92
- const source = record(data?.source);
93
- if (source?.kind !== "user")
94
- continue;
95
- if (event.seq > seq)
161
+ if (isHumanPrompt(event) && event.seq > seq)
96
162
  seq = event.seq;
97
163
  }
98
164
  return seq;
@@ -1 +1 @@
1
- {"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/integration/answer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/integration/answer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Why a memory call failed, in the coarse vocabulary the console's copy table
3
+ * speaks.
4
+ *
5
+ * The refusal is read off the plugin's stable `code` field rather than its
6
+ * message: a message is written for a log and gets reworded, and matching one
7
+ * here would mean a rename in another package silently turns a refusal into an
8
+ * unhandled fault. `cause` is checked too, because the storage seam wraps what
9
+ * the backend threw.
10
+ */
11
+ export function expertMemoryReasonOf(error) {
12
+ const code = errorCodeOf(error);
13
+ if (code === undefined)
14
+ return undefined;
15
+ switch (code) {
16
+ case "MEMORY_SCOPE_DENIED":
17
+ return "forbidden";
18
+ case "MEMORY_RECORD_MISSING":
19
+ return "memory-record-unknown";
20
+ case "STORAGE_UNAVAILABLE":
21
+ case "MEMORY_PROVIDER_MISSING":
22
+ return "memory-unavailable";
23
+ case "TASK_REJECTED":
24
+ return "invalid-memory";
25
+ default:
26
+ return undefined;
27
+ }
28
+ }
29
+ function errorCodeOf(error) {
30
+ for (let current = error; current !== undefined && current !== null; current = current instanceof Error ? current.cause : undefined) {
31
+ const code = current.code;
32
+ if (typeof code === "string" && code !== "")
33
+ return code;
34
+ if (!(current instanceof Error))
35
+ return undefined;
36
+ }
37
+ return undefined;
38
+ }
39
+ //# sourceMappingURL=expert-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expert-memory.js","sourceRoot":"","sources":["../../src/integration/expert-memory.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAc;IAOd,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,qBAAqB;YACxB,OAAO,WAAW,CAAC;QACrB,KAAK,uBAAuB;YAC1B,OAAO,uBAAuB,CAAC;QACjC,KAAK,qBAAqB,CAAC;QAC3B,KAAK,yBAAyB;YAC5B,OAAO,oBAAoB,CAAC;QAC9B,KAAK,eAAe;YAClB,OAAO,gBAAgB,CAAC;QAC1B;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,KACE,IAAI,OAAO,GAAY,KAAK,EAC5B,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EACzC,OAAO,GAAG,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAC9D,CAAC;QACD,MAAM,IAAI,GAAI,OAAuC,CAAC,IAAI,CAAC;QAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QACzD,IAAI,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;IACpD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { SessionId } from "@deepseek-ai/dsh-session/types";
3
3
  import { WorkspaceId } from "@deepseek-ai/dsh-workspace";
4
4
  import { prepareQaUserWorkspace } from "../user-workspace.js";
5
- import { answerAfter, lastPromptSeq } from "./answer.js";
5
+ import { answerAfter, answerForRequest, lastPromptSeq } from "./answer.js";
6
6
  import { attachmentPromptParts } from "./attachments.js";
7
7
  import { QaIntegrationTranscriptReader } from "./transcript-reader.js";
8
8
  /** Build the runner for one plugin instance. */
@@ -170,16 +170,22 @@ export function createQaIntegrationRunner(options) {
170
170
  if (!read.ok) {
171
171
  throw new Error(`the session log is unavailable (${read.reason})`);
172
172
  }
173
- // The prompt's own event may be missing from an empty snapshot, so the
174
- // floor is the later of the cursor taken before the question and the
175
- // newest human prompt the log knows about. Either way the answer is the
176
- // last assistant message after it, and no earlier turn can be read as
177
- // this one's answer.
178
- const projected = answerAfter(read.events, Math.max(floor, lastPromptSeq(read.events)));
173
+ // This request's own turn answers it. The harness echoes the prompt's rpc
174
+ // id onto the durable user row, so the turn is found by that id instead of
175
+ // by "the newest prompt in the log": two questions in flight on one chat
176
+ // commit two turns, and reading the newest of them answers each caller with
177
+ // the other's turn. The cursor fallback is for the one case correlation
178
+ // cannot serve — a prompt whose row the read did not reach yet — and it is
179
+ // the later of the cursor taken before the question and the newest human
180
+ // prompt, so no earlier turn can be read as this one's answer.
181
+ const projected = answerForRequest(read.events, requestId) ?? {
182
+ ...answerAfter(read.events, Math.max(floor, lastPromptSeq(read.events))),
183
+ turn: null,
184
+ };
179
185
  return Object.freeze({
180
186
  chatId,
181
187
  answer: projected.answer,
182
- sources: sourcesOf(chatId),
188
+ sources: sourcesOf(chatId, projected.turn),
183
189
  interrupted: projected.interrupted,
184
190
  });
185
191
  },
@@ -195,15 +201,21 @@ export function createQaIntegrationRunner(options) {
195
201
  },
196
202
  };
197
203
  /**
198
- * The evidence of the chat's latest turn, for the bridge's citations. The
199
- * provenance store materializes one bundle per turn; the newest is the one
200
- * that belongs to the answer just written. A deployment that switched
201
- * source collection off answers with an empty list rather than no answer.
204
+ * The evidence of one turn, for the bridge's citations. The provenance store
205
+ * materializes one bundle per turn, so the bundle named by the turn that
206
+ * answered is the one that belongs to the answer just written — the newest
207
+ * bundle is only the same thing while one turn is the last one in the chat.
208
+ * `turn` is null when the answer came from a log that named no turn for it,
209
+ * and the newest bundle is then the best the citation has. A deployment that
210
+ * switched source collection off answers with an empty list rather than no
211
+ * answer.
202
212
  */
203
- function sourcesOf(sessionId) {
213
+ function sourcesOf(sessionId, turn) {
204
214
  try {
205
215
  const bundles = options.provenance.bundles(sessionId);
206
- return bundles.at(-1)?.sources ?? [];
216
+ if (turn === null)
217
+ return bundles.at(-1)?.sources ?? [];
218
+ return bundles.find((bundle) => bundle.turn === turn)?.sources ?? [];
207
219
  }
208
220
  catch (error) {
209
221
  logger.warn("integration.sources-unavailable", {
@@ -1 +1 @@
1
- {"version":3,"file":"host-runner.js","sourceRoot":"","sources":["../../src/integration/host-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host-runner.js","sourceRoot":"","sources":["../../src/integration/host-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Per-account choices about the notices a finished turn may raise. Shape,
3
+ * defaults and the normalization both halves of the plugin agree on — the
4
+ * accounts store reads a record it cannot trust, and the settings form sends
5
+ * one back. Free of Node built-ins for the same reason starters.ts is: the
6
+ * browser bundle imports it too.
7
+ */
8
+ /** The channels a reader can choose between, in the order the form lists them. */
9
+ const NOTIFICATION_CHANNELS = ["inApp", "desktop"];
10
+ /**
11
+ * What an account that never opened the notifications form gets.
12
+ *
13
+ * The in-page line is the shipped default of the feature itself, so an
14
+ * untouched account keeps behaving as it did before the form existed. The
15
+ * desktop channel stays off until asked for: raising an operating-system notice
16
+ * is the one choice that leaves the page, and a stand where the browser was
17
+ * never asked must not make it on the account's behalf.
18
+ */
19
+ export function emptyNotifications() {
20
+ return { inApp: true, desktop: false };
21
+ }
22
+ function asRecord(value) {
23
+ return value !== null && typeof value === "object" && !Array.isArray(value)
24
+ ? value
25
+ : undefined;
26
+ }
27
+ /**
28
+ * Read one stored (or wire-delivered) notifications record into its public
29
+ * shape. Unknown or hand-edited input degrades to the readable subset rather
30
+ * than throwing, mirroring the starters read path: a malformed record must
31
+ * never cost the account its session.
32
+ */
33
+ export function normalizeNotifications(value) {
34
+ const raw = asRecord(value);
35
+ if (raw === undefined)
36
+ return emptyNotifications();
37
+ const defaults = emptyNotifications();
38
+ return {
39
+ inApp: typeof raw.inApp === "boolean" ? raw.inApp : defaults.inApp,
40
+ desktop: typeof raw.desktop === "boolean" ? raw.desktop : defaults.desktop,
41
+ };
42
+ }
43
+ /**
44
+ * Validate one full-replace notifications write. Both channels are required: a
45
+ * payload that names only one would silently reset the other, and the form
46
+ * always sends the pair it was rendered with.
47
+ */
48
+ export function validateNotificationsWrite(input) {
49
+ const raw = asRecord(input);
50
+ if (raw === undefined) {
51
+ return {
52
+ ok: false,
53
+ message: "the notifications payload is not an object",
54
+ };
55
+ }
56
+ for (const channel of NOTIFICATION_CHANNELS) {
57
+ if (typeof raw[channel] !== "boolean") {
58
+ return { ok: false, message: `${channel} must be a boolean` };
59
+ }
60
+ }
61
+ return {
62
+ ok: true,
63
+ value: { inApp: raw.inApp === true, desktop: raw.desktop === true },
64
+ };
65
+ }
66
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH,kFAAkF;AAClF,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC;AAE5D;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,kBAAkB,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IACtC,OAAO;QACL,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK;QAClE,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO;KAC3E,CAAC;AACJ,CAAC;AAMD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAAc;IAEd,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,4CAA4C;SACtD,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,qBAAqB,EAAE,CAAC;QAC5C,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;YACtC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,oBAAoB,EAAE,CAAC;QAChE,CAAC;IACH,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,EAAE;KACpE,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/personal-skills/errors.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAElC,MAAM;IADjB,YACW,MAAkC,EAC3C,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/personal-skills/errors.ts"],"names":[],"mappings":"AAgBA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAElC,MAAM;IADjB,YACW,MAAkC,EAC3C,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
@@ -197,6 +197,12 @@ export class QaPersonalSkills {
197
197
  throw new QaPersonalSkillError("skill-not-found", `no skill directory named ${name}`);
198
198
  }
199
199
  this.assertRevision(name, input.expectedRevision, current.revision);
200
+ if (current.truncated && input.confirmPartialOverwrite !== true) {
201
+ // The editor holds a head it could read, not the document. A save writes
202
+ // what it holds, so the tail nobody loaded would vanish with no trace:
203
+ // the client has to say it knows before that becomes a write.
204
+ throw new QaPersonalSkillError("skill-truncated", `skill ${name} is larger than the read ceiling and was loaded only partly`);
205
+ }
200
206
  const text = serializeSkillFile({
201
207
  ...prepared.draft,
202
208
  // Foreign frontmatter is read from the file, not from the browser: the
@@ -402,6 +408,7 @@ export class QaPersonalSkills {
402
408
  contents: undefined,
403
409
  diagnostics: [],
404
410
  resourceCount: 0,
411
+ truncated: false,
405
412
  };
406
413
  let directory;
407
414
  try {
@@ -431,6 +438,7 @@ export class QaPersonalSkills {
431
438
  revision: "",
432
439
  updatedAt: null,
433
440
  contents: undefined,
441
+ truncated: false,
434
442
  diagnostics: [
435
443
  ...resources.diagnostics,
436
444
  {
@@ -445,6 +453,18 @@ export class QaPersonalSkills {
445
453
  const parsed = parseSkillFile(read.text);
446
454
  const diagnostics = [
447
455
  ...resources.diagnostics,
456
+ // Ahead of the parse findings: a body that stops mid-document explains
457
+ // why what follows it reads as broken.
458
+ ...(read.truncated
459
+ ? [
460
+ {
461
+ code: "skill-file-truncated",
462
+ severity: "error",
463
+ field: null,
464
+ detail: String(read.sizeBytes),
465
+ },
466
+ ]
467
+ : []),
448
468
  ...(parsed.ok ? parsed.value.warnings : []),
449
469
  ];
450
470
  if (!parsed.ok) {
@@ -463,7 +483,7 @@ export class QaPersonalSkills {
463
483
  modelInvocable: parsed.value.modelInvocable,
464
484
  userInvocable: parsed.value.userInvocable,
465
485
  allowedTools: parsed.value.allowedTools,
466
- sizeBytes: skillFileBytes(read.text),
486
+ sizeBytes: read.sizeBytes,
467
487
  maxBytes,
468
488
  availableTools: [...this.availableTools()],
469
489
  }));
@@ -479,10 +499,13 @@ export class QaPersonalSkills {
479
499
  return {
480
500
  ...base,
481
501
  raw: read.text,
482
- revision: hashText(read.text),
502
+ // The whole file, not the loaded prefix: an append behind the ceiling has
503
+ // to move the revision, or an update would overwrite bytes it never saw.
504
+ revision: hashFileBytes(filePath) ?? hashText(read.text),
483
505
  updatedAt: read.updatedAt,
484
506
  contents: parsed.ok ? parsed.value : undefined,
485
507
  diagnostics,
508
+ truncated: read.truncated,
486
509
  };
487
510
  }
488
511
  resources(directory) {
@@ -677,6 +700,7 @@ export class QaPersonalSkills {
677
700
  body: contents?.body ?? skillFileBody(stored.raw),
678
701
  extraFrontmatter: contents?.extraFrontmatter ?? {},
679
702
  sourcePath: stored.filePath,
703
+ truncated: stored.truncated,
680
704
  preview: contents === undefined ? stored.raw : serializeSkillFile(contents),
681
705
  };
682
706
  }
@@ -726,12 +750,17 @@ export class QaPersonalSkills {
726
750
  * since changed reports as absent rather than as a claim about the present.
727
751
  */
728
752
  adminEdits(roots) {
729
- const read = readSkillText(path.join(roots.skills, QA_SKILL_ADMIN_EDITS_FILE), ADMIN_EDITS_MAX_BYTES);
730
- if (read === undefined)
753
+ const sidecar = readSkillText(path.join(roots.skills, QA_SKILL_ADMIN_EDITS_FILE), ADMIN_EDITS_MAX_BYTES);
754
+ if (sidecar === undefined)
731
755
  return new Map();
756
+ // Only the text is taken, and the truncation flag is left unread on
757
+ // purpose: a half-read sidecar fails to parse and answers "no marks",
758
+ // which is the right degradation for a badge — and, unlike a skill file,
759
+ // this read has no write behind it that could lose the rest.
760
+ const { text } = sidecar;
732
761
  let parsed;
733
762
  try {
734
- parsed = JSON.parse(read.text);
763
+ parsed = JSON.parse(text);
735
764
  }
736
765
  catch {
737
766
  return new Map();
@@ -861,6 +890,38 @@ function qaUserWorkspaceFromCwd(cwd) {
861
890
  function hashText(text) {
862
891
  return createHash("sha256").update(Buffer.from(text, "utf8")).digest("hex");
863
892
  }
893
+ /** One chunk of the streaming hash below. */
894
+ const HASH_CHUNK_BYTES = 64 * 1024;
895
+ /**
896
+ * sha256 of a whole file, read through a bounded buffer.
897
+ *
898
+ * The revision has to describe every byte a skill file holds, including the
899
+ * ones a size-capped read never loaded, and hashing must not put a huge file
900
+ * back into memory. Returns undefined when the file cannot be read: the caller
901
+ * falls back to the bytes it did see.
902
+ */
903
+ function hashFileBytes(filePath) {
904
+ const hash = createHash("sha256");
905
+ const buffer = Buffer.alloc(HASH_CHUNK_BYTES);
906
+ try {
907
+ const handle = openSync(filePath, "r");
908
+ try {
909
+ for (;;) {
910
+ const read = readSync(handle, buffer, 0, buffer.length, null);
911
+ if (read === 0)
912
+ break;
913
+ hash.update(buffer.subarray(0, read));
914
+ }
915
+ }
916
+ finally {
917
+ closeSync(handle);
918
+ }
919
+ }
920
+ catch {
921
+ return undefined;
922
+ }
923
+ return hash.digest("hex");
924
+ }
864
925
  function pathExists(input) {
865
926
  try {
866
927
  statSync(input);
@@ -874,6 +935,9 @@ function pathExists(input) {
874
935
  * Read one skill file, refusing to hold an unbounded file in memory: an
875
936
  * oversized `SKILL.md` is read only up to the ceiling and reported by the
876
937
  * validator, which keeps the editor usable instead of the Host unresponsive.
938
+ * The prefix is never presented as the document: the answer carries the real
939
+ * size and says plainly that the read stopped early, so a save can refuse to
940
+ * overwrite bytes nobody saw.
877
941
  * The file is lstat-ed, so a symlinked `SKILL.md` is treated as absent rather
878
942
  * than followed out of the account's directory.
879
943
  */
@@ -892,7 +956,12 @@ function readSkillText(filePath, maxBytes) {
892
956
  }
893
957
  if (size <= maxBytes) {
894
958
  try {
895
- return { text: readFileSync(filePath, "utf8"), updatedAt };
959
+ return {
960
+ text: readFileSync(filePath, "utf8"),
961
+ updatedAt,
962
+ sizeBytes: size,
963
+ truncated: false,
964
+ };
896
965
  }
897
966
  catch {
898
967
  return undefined;
@@ -903,7 +972,12 @@ function readSkillText(filePath, maxBytes) {
903
972
  try {
904
973
  const buffer = Buffer.alloc(maxBytes);
905
974
  const read = readSync(handle, buffer, 0, maxBytes, 0);
906
- return { text: buffer.subarray(0, read).toString("utf8"), updatedAt };
975
+ return {
976
+ text: buffer.subarray(0, read).toString("utf8"),
977
+ updatedAt,
978
+ sizeBytes: size,
979
+ truncated: true,
980
+ };
907
981
  }
908
982
  finally {
909
983
  closeSync(handle);