@agimon-ai/doompi-author 0.0.1-alpha.2

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 (282) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/adapters/authorApi.cjs +2 -0
  5. package/dist/adapters/authorApi.cjs.map +1 -0
  6. package/dist/adapters/authorBridgeApi.cjs +2 -0
  7. package/dist/adapters/authorBridgeApi.cjs.map +1 -0
  8. package/dist/adapters/authorDocumentApi.cjs +2 -0
  9. package/dist/adapters/authorDocumentApi.cjs.map +1 -0
  10. package/dist/adapters/pi/authorBridgeClient.cjs +2 -0
  11. package/dist/adapters/pi/authorBridgeClient.cjs.map +1 -0
  12. package/dist/adapters/pi/authorTools.cjs +2 -0
  13. package/dist/adapters/pi/authorTools.cjs.map +1 -0
  14. package/dist/adapters/pi/extension.cjs +2 -0
  15. package/dist/adapters/pi/extension.cjs.map +1 -0
  16. package/dist/adapters/structuredDocuments/common.cjs +2 -0
  17. package/dist/adapters/structuredDocuments/common.cjs.map +1 -0
  18. package/dist/adapters/structuredDocuments/csv.cjs +7 -0
  19. package/dist/adapters/structuredDocuments/csv.cjs.map +1 -0
  20. package/dist/adapters/structuredDocuments/index.cjs +2 -0
  21. package/dist/adapters/structuredDocuments/index.cjs.map +1 -0
  22. package/dist/adapters/structuredDocuments/markdownSlides.cjs +6 -0
  23. package/dist/adapters/structuredDocuments/markdownSlides.cjs.map +1 -0
  24. package/dist/adapters/structuredDocuments/ooxmlArchive.cjs +2 -0
  25. package/dist/adapters/structuredDocuments/ooxmlArchive.cjs.map +1 -0
  26. package/dist/adapters/structuredDocuments/pptx.cjs +2 -0
  27. package/dist/adapters/structuredDocuments/pptx.cjs.map +1 -0
  28. package/dist/adapters/structuredDocuments/xlsx.cjs +2 -0
  29. package/dist/adapters/structuredDocuments/xlsx.cjs.map +1 -0
  30. package/dist/adapters/structuredDocuments/xmlText.cjs +2 -0
  31. package/dist/adapters/structuredDocuments/xmlText.cjs.map +1 -0
  32. package/dist/adapters/webAuthorChannel.cjs +2 -0
  33. package/dist/adapters/webAuthorChannel.cjs.map +1 -0
  34. package/dist/commands/doomAuthorCommand.cjs +2 -0
  35. package/dist/commands/doomAuthorCommand.cjs.map +1 -0
  36. package/dist/container/index.cjs +2 -0
  37. package/dist/container/index.cjs.map +1 -0
  38. package/dist/extensions/pi.cjs +1 -0
  39. package/dist/extensions/pi.d.cts +2 -0
  40. package/dist/extensions/pi.d.mts +2 -0
  41. package/dist/extensions/pi.mjs +1 -0
  42. package/dist/index.cjs +1 -0
  43. package/dist/index.d.cts +21 -0
  44. package/dist/index.d.mts +21 -0
  45. package/dist/index.mjs +1 -0
  46. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.cts +6 -0
  47. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.cts.map +1 -0
  48. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.mts +6 -0
  49. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.mts.map +1 -0
  50. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.cts +7 -0
  51. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.cts.map +1 -0
  52. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.mts +7 -0
  53. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.mts.map +1 -0
  54. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.cts +12 -0
  55. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.cts.map +1 -0
  56. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.mts +12 -0
  57. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.mts.map +1 -0
  58. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.cts +12 -0
  59. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.cts.map +1 -0
  60. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.mts +12 -0
  61. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.mts.map +1 -0
  62. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.cts +9 -0
  63. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.cts.map +1 -0
  64. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.mts +9 -0
  65. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.mts.map +1 -0
  66. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.cts +4 -0
  67. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.cts.map +1 -0
  68. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.mts +4 -0
  69. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.mts.map +1 -0
  70. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.cts +9 -0
  71. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.cts.map +1 -0
  72. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.mts +9 -0
  73. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.mts.map +1 -0
  74. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.cts +8 -0
  75. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.cts.map +1 -0
  76. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.mts +8 -0
  77. package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.mts.map +1 -0
  78. package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.cts +15 -0
  79. package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.cts.map +1 -0
  80. package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.mts +15 -0
  81. package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.mts.map +1 -0
  82. package/dist/packages/minor/doompi-author/src/adapters/authorApi.mjs +2 -0
  83. package/dist/packages/minor/doompi-author/src/adapters/authorApi.mjs.map +1 -0
  84. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.cts +6 -0
  85. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.cts.map +1 -0
  86. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.mts +6 -0
  87. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.mts.map +1 -0
  88. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.mjs +2 -0
  89. package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.mjs.map +1 -0
  90. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.cts +11 -0
  91. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.cts.map +1 -0
  92. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.mts +11 -0
  93. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.mts.map +1 -0
  94. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.mjs +2 -0
  95. package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.mjs.map +1 -0
  96. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.cts +18 -0
  97. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.cts.map +1 -0
  98. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.mts +18 -0
  99. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.mts.map +1 -0
  100. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.mjs +2 -0
  101. package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.mjs.map +1 -0
  102. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.cts +9 -0
  103. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.cts.map +1 -0
  104. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.mts +9 -0
  105. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.mts.map +1 -0
  106. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.mjs +2 -0
  107. package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.mjs.map +1 -0
  108. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.cts +19 -0
  109. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.cts.map +1 -0
  110. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.mts +19 -0
  111. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.mts.map +1 -0
  112. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.mjs +2 -0
  113. package/dist/packages/minor/doompi-author/src/adapters/pi/extension.mjs.map +1 -0
  114. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/common.mjs +2 -0
  115. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/common.mjs.map +1 -0
  116. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.cts +7 -0
  117. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.cts.map +1 -0
  118. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.mts +7 -0
  119. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.mts.map +1 -0
  120. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.mjs +7 -0
  121. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.mjs.map +1 -0
  122. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.cts +13 -0
  123. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.cts.map +1 -0
  124. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.mts +13 -0
  125. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.mts.map +1 -0
  126. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.mjs +2 -0
  127. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.mjs.map +1 -0
  128. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.cts +7 -0
  129. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.cts.map +1 -0
  130. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.mts +7 -0
  131. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.mts.map +1 -0
  132. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.mjs +6 -0
  133. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.mjs.map +1 -0
  134. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.cts +13 -0
  135. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.cts.map +1 -0
  136. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.mts +13 -0
  137. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.mts.map +1 -0
  138. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.mjs +2 -0
  139. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.mjs.map +1 -0
  140. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.cts +7 -0
  141. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.cts.map +1 -0
  142. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.mts +7 -0
  143. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.mts.map +1 -0
  144. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.mjs +2 -0
  145. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.mjs.map +1 -0
  146. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.cts +7 -0
  147. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.cts.map +1 -0
  148. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.mts +7 -0
  149. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.mts.map +1 -0
  150. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.mjs +2 -0
  151. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.mjs.map +1 -0
  152. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xmlText.mjs +2 -0
  153. package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xmlText.mjs.map +1 -0
  154. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.cts +6 -0
  155. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.cts.map +1 -0
  156. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.mts +6 -0
  157. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.mts.map +1 -0
  158. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.mjs +2 -0
  159. package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.mjs.map +1 -0
  160. package/dist/packages/minor/doompi-author/src/commands/doomAuthorCommand.mjs +2 -0
  161. package/dist/packages/minor/doompi-author/src/commands/doomAuthorCommand.mjs.map +1 -0
  162. package/dist/packages/minor/doompi-author/src/container/index.d.cts +5 -0
  163. package/dist/packages/minor/doompi-author/src/container/index.d.cts.map +1 -0
  164. package/dist/packages/minor/doompi-author/src/container/index.d.mts +5 -0
  165. package/dist/packages/minor/doompi-author/src/container/index.d.mts.map +1 -0
  166. package/dist/packages/minor/doompi-author/src/container/index.mjs +2 -0
  167. package/dist/packages/minor/doompi-author/src/container/index.mjs.map +1 -0
  168. package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.cts +16 -0
  169. package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.cts.map +1 -0
  170. package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.mts +16 -0
  171. package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.mts.map +1 -0
  172. package/dist/packages/minor/doompi-author/src/schemas/authorTools.mjs +2 -0
  173. package/dist/packages/minor/doompi-author/src/schemas/authorTools.mjs.map +1 -0
  174. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.cts +31 -0
  175. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.cts.map +1 -0
  176. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.mts +31 -0
  177. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.mts.map +1 -0
  178. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.mjs +2 -0
  179. package/dist/packages/minor/doompi-author/src/services/authorBridgeState.mjs.map +1 -0
  180. package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.cts +10 -0
  181. package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.cts.map +1 -0
  182. package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.mts +10 -0
  183. package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.mts.map +1 -0
  184. package/dist/packages/minor/doompi-author/src/services/authorMode.d.cts +19 -0
  185. package/dist/packages/minor/doompi-author/src/services/authorMode.d.cts.map +1 -0
  186. package/dist/packages/minor/doompi-author/src/services/authorMode.d.mts +19 -0
  187. package/dist/packages/minor/doompi-author/src/services/authorMode.d.mts.map +1 -0
  188. package/dist/packages/minor/doompi-author/src/services/authorMode.mjs +3 -0
  189. package/dist/packages/minor/doompi-author/src/services/authorMode.mjs.map +1 -0
  190. package/dist/packages/minor/doompi-author/src/services/extensionService.d.cts +7 -0
  191. package/dist/packages/minor/doompi-author/src/services/extensionService.d.cts.map +1 -0
  192. package/dist/packages/minor/doompi-author/src/services/extensionService.d.mts +7 -0
  193. package/dist/packages/minor/doompi-author/src/services/extensionService.d.mts.map +1 -0
  194. package/dist/packages/minor/doompi-author/src/services/extensionService.mjs +2 -0
  195. package/dist/packages/minor/doompi-author/src/services/extensionService.mjs.map +1 -0
  196. package/dist/packages/minor/doompi-author/src/types/author.d.cts +39 -0
  197. package/dist/packages/minor/doompi-author/src/types/author.d.cts.map +1 -0
  198. package/dist/packages/minor/doompi-author/src/types/author.d.mts +39 -0
  199. package/dist/packages/minor/doompi-author/src/types/author.d.mts.map +1 -0
  200. package/dist/packages/minor/doompi-author/src/types/author.mjs +2 -0
  201. package/dist/packages/minor/doompi-author/src/types/author.mjs.map +1 -0
  202. package/dist/packages/minor/doompi-author/src/types/authorApi.d.cts +23 -0
  203. package/dist/packages/minor/doompi-author/src/types/authorApi.d.cts.map +1 -0
  204. package/dist/packages/minor/doompi-author/src/types/authorApi.d.mts +23 -0
  205. package/dist/packages/minor/doompi-author/src/types/authorApi.d.mts.map +1 -0
  206. package/dist/packages/minor/doompi-author/src/types/authorApi.mjs +2 -0
  207. package/dist/packages/minor/doompi-author/src/types/authorApi.mjs.map +1 -0
  208. package/dist/packages/minor/doompi-author/src/types/extension.d.cts +16 -0
  209. package/dist/packages/minor/doompi-author/src/types/extension.d.cts.map +1 -0
  210. package/dist/packages/minor/doompi-author/src/types/extension.d.mts +16 -0
  211. package/dist/packages/minor/doompi-author/src/types/extension.d.mts.map +1 -0
  212. package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.cts +60 -0
  213. package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.cts.map +1 -0
  214. package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.mts +60 -0
  215. package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.mts.map +1 -0
  216. package/dist/packages/minor/doompi-author/src/types/webAuthor.d.cts +67 -0
  217. package/dist/packages/minor/doompi-author/src/types/webAuthor.d.cts.map +1 -0
  218. package/dist/packages/minor/doompi-author/src/types/webAuthor.d.mts +67 -0
  219. package/dist/packages/minor/doompi-author/src/types/webAuthor.d.mts.map +1 -0
  220. package/dist/packages/minor/doompi-author/src/types/webAuthor.mjs +2 -0
  221. package/dist/packages/minor/doompi-author/src/types/webAuthor.mjs.map +1 -0
  222. package/dist/schemas/authorTools.cjs +2 -0
  223. package/dist/schemas/authorTools.cjs.map +1 -0
  224. package/dist/services/authorBridgeState.cjs +2 -0
  225. package/dist/services/authorBridgeState.cjs.map +1 -0
  226. package/dist/services/authorMode.cjs +3 -0
  227. package/dist/services/authorMode.cjs.map +1 -0
  228. package/dist/services/extensionService.cjs +2 -0
  229. package/dist/services/extensionService.cjs.map +1 -0
  230. package/dist/sessionApi.cjs +1 -0
  231. package/dist/sessionApi.d.cts +7 -0
  232. package/dist/sessionApi.d.mts +7 -0
  233. package/dist/sessionApi.mjs +1 -0
  234. package/dist/types/author.cjs +2 -0
  235. package/dist/types/author.cjs.map +1 -0
  236. package/dist/types/authorApi.cjs +2 -0
  237. package/dist/types/authorApi.cjs.map +1 -0
  238. package/dist/types/webAuthor.cjs +2 -0
  239. package/dist/types/webAuthor.cjs.map +1 -0
  240. package/dist/webHub.cjs +1 -0
  241. package/dist/webHub.d.cts +2 -0
  242. package/dist/webHub.d.mts +2 -0
  243. package/dist/webHub.mjs +1 -0
  244. package/llms.txt +11 -0
  245. package/package.json +140 -0
  246. package/src/exports/webClient.ts +76 -0
  247. package/src/prompts/doompi-use-author/SKILL.md +17 -0
  248. package/src/types/author.ts +45 -0
  249. package/src/types/structuredDocuments.ts +63 -0
  250. package/src/types/webAuthor.ts +85 -0
  251. package/src/web/api/authorBroker.ts +14 -0
  252. package/src/web/api/authorBrowserBridge.ts +225 -0
  253. package/src/web/api/authorFiles.ts +219 -0
  254. package/src/web/api/authorMedia.ts +19 -0
  255. package/src/web/api/authorRuntime.ts +164 -0
  256. package/src/web/components/AuthorDocumentPanel.tsx +232 -0
  257. package/src/web/components/AuthorGridOverlay.tsx +81 -0
  258. package/src/web/components/AuthorMediaPreview.tsx +41 -0
  259. package/src/web/components/AuthorMediaView.tsx +356 -0
  260. package/src/web/components/AuthorPanel.tsx +105 -0
  261. package/src/web/components/AuthorRegionDrafts.tsx +102 -0
  262. package/src/web/components/AuthorRequestLog.tsx +179 -0
  263. package/src/web/components/AuthorStructuredView.tsx +121 -0
  264. package/src/web/components/AuthorTextView.tsx +97 -0
  265. package/src/web/components/AuthorToolPalette.tsx +103 -0
  266. package/src/web/components/AuthorVideoControls.tsx +111 -0
  267. package/src/web/components/DescribeAuthorToolsToolCard.tsx +50 -0
  268. package/src/web/components/OpenAuthoringFileToolCard.tsx +66 -0
  269. package/src/web/components/UseAuthorToolsToolCard.tsx +50 -0
  270. package/src/web/index.ts +68 -0
  271. package/src/web/lib/authorGrid.ts +124 -0
  272. package/src/web/lib/authorRegions.ts +30 -0
  273. package/src/web/lib/authorViewportTypes.ts +202 -0
  274. package/src/web/lib/describeAuthorToolsToolRender.ts +20 -0
  275. package/src/web/lib/useAuthorToolsToolRender.ts +20 -0
  276. package/src/web/stores/authorCapture.ts +322 -0
  277. package/src/web/stores/authorGridTools.ts +316 -0
  278. package/src/web/stores/authorProfiles.ts +130 -0
  279. package/src/web/stores/authorRequestLifecycle.ts +82 -0
  280. package/src/web/stores/authorStore.ts +60 -0
  281. package/src/web/stores/authorWorkspaceStore.ts +525 -0
  282. package/src/web/tsconfig.json +22 -0
@@ -0,0 +1,322 @@
1
+ import type { ComposerCapture, WebPluginContextItem } from '@agimon-ai/doompi-web-contracts';
2
+ import type { AuthorWorkspaceDocument } from './authorWorkspaceStore.ts';
3
+ import type { AuthorCrop, AuthorNativeAnchor, AuthorRegionDraft } from '../lib/authorViewportTypes.ts';
4
+
5
+ export const AUTHOR_CAPTURE_MAX_DIMENSION = 1600;
6
+ export const AUTHOR_CAPTURE_MAX_BYTES = 2 * 1024 * 1024;
7
+ export const AUTHOR_PACKET_MAX_BYTES = 64 * 1024;
8
+ export const AUTHOR_COMMENT_MAX_BYTES = 2 * 1024;
9
+ export const AUTHOR_QUOTE_MAX_BYTES = 4 * 1024;
10
+ export const AUTHOR_REGION_COLORS = [
11
+ '#ff5f57',
12
+ '#00c2ff',
13
+ '#ffd166',
14
+ '#b388ff',
15
+ '#4ade80',
16
+ '#ff8c42',
17
+ '#f472b6',
18
+ '#2dd4bf',
19
+ '#a3e635',
20
+ '#60a5fa',
21
+ '#e879f9',
22
+ '#facc15',
23
+ '#34d399',
24
+ '#fb7185',
25
+ '#818cf8',
26
+ '#22d3ee',
27
+ ] as const;
28
+
29
+ function annotationForeground(color: string): '#101216' | '#ffffff' {
30
+ const red = Number.parseInt(color.slice(1, 3), 16);
31
+ const green = Number.parseInt(color.slice(3, 5), 16);
32
+ const blue = Number.parseInt(color.slice(5, 7), 16);
33
+ return red * 299 + green * 587 + blue * 114 >= 150_000 ? '#101216' : '#ffffff';
34
+ }
35
+
36
+ export interface AuthorCapturePacketRegion {
37
+ id: string;
38
+ ordinal: number;
39
+ comment: string;
40
+ quote?: string;
41
+ anchor: AuthorNativeAnchor;
42
+ viewport: AuthorRegionDraft['viewport'];
43
+ voiceGrid?: AuthorRegionDraft['voiceGrid'];
44
+ }
45
+
46
+ export interface AuthorCapturePacket {
47
+ version: 1;
48
+ captureId: string;
49
+ capturedAt: number;
50
+ document: { path: string; kind: AuthorWorkspaceDocument['kind']; revision: number; sourceSha256?: string };
51
+ regions: AuthorCapturePacketRegion[];
52
+ }
53
+
54
+ export interface AuthorCaptureProvider {
55
+ capture(signal?: AbortSignal): Promise<{ data: string; mimeType: 'image/png' | 'image/jpeg' }>;
56
+ }
57
+
58
+ const bytes = (value: string): number => new TextEncoder().encode(value).byteLength;
59
+
60
+ function utf8Prefix(value: string, limit: number): string {
61
+ if (bytes(value) <= limit) return value;
62
+ let low = 0;
63
+ let high = value.length;
64
+ while (low < high) {
65
+ const middle = Math.ceil((low + high) / 2);
66
+ if (bytes(value.slice(0, middle)) <= limit) low = middle;
67
+ else high = middle - 1;
68
+ }
69
+ return value.slice(0, low);
70
+ }
71
+
72
+ export function createAuthorCapturePacket(
73
+ captureId: string,
74
+ capturedAt: number,
75
+ document: AuthorWorkspaceDocument,
76
+ regions: readonly AuthorRegionDraft[],
77
+ ): AuthorCapturePacket {
78
+ if (regions.length === 0 || regions.length > 16) throw new Error('Capture requires between 1 and 16 regions.');
79
+ const packet: AuthorCapturePacket = {
80
+ version: 1,
81
+ captureId,
82
+ capturedAt,
83
+ document: {
84
+ path: document.path,
85
+ kind: document.kind,
86
+ revision: document.version,
87
+ ...(document.sourceSha256 === undefined ? {} : { sourceSha256: document.sourceSha256 }),
88
+ },
89
+ regions: regions.map((region, index) => {
90
+ if (
91
+ region.documentPath !== document.path ||
92
+ region.revision !== document.version ||
93
+ region.sourceSha256 !== document.sourceSha256
94
+ ) {
95
+ throw new Error(`Region ${String(index + 1)} is stale for the focused document.`);
96
+ }
97
+ if (region.comment.trim() === '') throw new Error(`Region ${String(index + 1)} requires a comment.`);
98
+ if (bytes(region.comment) > AUTHOR_COMMENT_MAX_BYTES) {
99
+ throw new Error(`Region ${String(index + 1)} comment exceeds 2 KiB.`);
100
+ }
101
+ return {
102
+ id: region.id,
103
+ ordinal: index + 1,
104
+ comment: region.comment,
105
+ ...(region.quote === undefined ? {} : { quote: utf8Prefix(region.quote, AUTHOR_QUOTE_MAX_BYTES) }),
106
+ anchor: structuredClone(region.anchor),
107
+ viewport: { ...region.viewport },
108
+ ...(region.voiceGrid === undefined ? {} : { voiceGrid: { ...region.voiceGrid } }),
109
+ };
110
+ }),
111
+ };
112
+ if (bytes(JSON.stringify(packet)) > AUTHOR_PACKET_MAX_BYTES) throw new Error('Author capture packet exceeds 64 KiB.');
113
+ return packet;
114
+ }
115
+
116
+ function rectLocation(rect: AuthorCrop): string {
117
+ const percent = (value: number) => `${String(Math.round(value * 1_000) / 10)}%`;
118
+ return `x ${percent(rect.x)}, y ${percent(rect.y)}, w ${percent(rect.width)}, h ${percent(rect.height)}`;
119
+ }
120
+
121
+ function anchorLocation(anchor: AuthorNativeAnchor): string {
122
+ switch (anchor.kind) {
123
+ case 'text-range':
124
+ return anchor.startLine === anchor.endLine
125
+ ? `line ${String(anchor.startLine)}`
126
+ : `lines ${String(anchor.startLine)}-${String(anchor.endLine)}`;
127
+ case 'cell':
128
+ return `${anchor.sheet === undefined ? '' : `${anchor.sheet}!`}${anchor.location}`;
129
+ case 'slide-element':
130
+ return `slide ${String(anchor.slide)}: ${anchor.location}`;
131
+ case 'image-rect':
132
+ return `image ${rectLocation(anchor.rect)}`;
133
+ case 'pdf-page-rect':
134
+ return `page ${String(anchor.page)}, ${rectLocation(anchor.rect)}`;
135
+ case 'video-time-rect':
136
+ return `time ${anchor.timeSeconds.toFixed(3)}s${anchor.frame === undefined ? '' : `, frame ${String(anchor.frame)}`}, ${rectLocation(anchor.rect)}`;
137
+ }
138
+ }
139
+ export function authorCaptureContext(packet: AuthorCapturePacket): WebPluginContextItem {
140
+ const metadata = JSON.stringify(packet);
141
+ if (bytes(metadata) > AUTHOR_PACKET_MAX_BYTES) throw new Error('Author capture packet exceeds 64 KiB.');
142
+ const content = packet.regions
143
+ .map(
144
+ (region) =>
145
+ `(${String(region.ordinal)}) ${region.comment} [${anchorLocation(region.anchor)}]${region.quote ? `\nQuoted text: ${region.quote}` : ''}`,
146
+ )
147
+ .join('\n\n');
148
+ return {
149
+ kind: 'author-capture',
150
+ source: 'author',
151
+ id: packet.captureId,
152
+ label: `${packet.regions.length} region${packet.regions.length === 1 ? '' : 's'} · ${packet.document.path}`,
153
+ content,
154
+ metadata,
155
+ };
156
+ }
157
+
158
+ function canvasBlob(canvas: HTMLCanvasElement, type: 'image/png' | 'image/jpeg', quality?: number): Promise<Blob> {
159
+ return new Promise((resolve, reject) => {
160
+ canvas.toBlob(
161
+ (blob) => (blob === null ? reject(new Error('Unable to capture viewport')) : resolve(blob)),
162
+ type,
163
+ quality,
164
+ );
165
+ });
166
+ }
167
+
168
+ async function base64(blob: Blob): Promise<string> {
169
+ const bytes = new Uint8Array(await blob.arrayBuffer());
170
+ let binary = '';
171
+ for (let offset = 0; offset < bytes.length; offset += 0x8000) {
172
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));
173
+ }
174
+ return btoa(binary);
175
+ }
176
+
177
+ function throwIfAborted(signal?: AbortSignal): void {
178
+ if (signal?.aborted === true) throw signal.reason;
179
+ }
180
+
181
+ async function boundedCanvasCapture(
182
+ canvas: HTMLCanvasElement,
183
+ ): Promise<{ data: string; mimeType: 'image/png' | 'image/jpeg' }> {
184
+ let mimeType: 'image/png' | 'image/jpeg' = 'image/png';
185
+ let blob = await canvasBlob(canvas, mimeType);
186
+ for (const quality of [0.9, 0.75, 0.6, 0.45, 0.3]) {
187
+ if (blob.size <= AUTHOR_CAPTURE_MAX_BYTES) break;
188
+ mimeType = 'image/jpeg';
189
+ blob = await canvasBlob(canvas, mimeType, quality);
190
+ }
191
+ if (blob.size > AUTHOR_CAPTURE_MAX_BYTES) throw new Error('Viewport capture exceeds 2 MiB');
192
+ return { data: await base64(blob), mimeType };
193
+ }
194
+
195
+ export function imageCaptureProvider(image: HTMLImageElement, crop?: AuthorCrop): AuthorCaptureProvider {
196
+ return {
197
+ async capture(signal) {
198
+ throwIfAborted(signal);
199
+ const normalized = crop ?? { x: 0, y: 0, width: 1, height: 1 };
200
+ const source = {
201
+ x: normalized.x * image.naturalWidth,
202
+ y: normalized.y * image.naturalHeight,
203
+ width: normalized.width * image.naturalWidth,
204
+ height: normalized.height * image.naturalHeight,
205
+ };
206
+ if (source.width <= 0 || source.height <= 0) throw new Error('Image is not ready to capture');
207
+ const scale = Math.min(1, AUTHOR_CAPTURE_MAX_DIMENSION / Math.max(source.width, source.height));
208
+ const canvas = document.createElement('canvas');
209
+ canvas.width = Math.max(1, Math.round(source.width * scale));
210
+ canvas.height = Math.max(1, Math.round(source.height * scale));
211
+ const context = canvas.getContext('2d');
212
+ if (context === null) throw new Error('Canvas is unavailable');
213
+ context.drawImage(image, source.x, source.y, source.width, source.height, 0, 0, canvas.width, canvas.height);
214
+ const capture = await boundedCanvasCapture(canvas);
215
+ throwIfAborted(signal);
216
+ return capture;
217
+ },
218
+ };
219
+ }
220
+
221
+ function loadImage(url: string): Promise<HTMLImageElement> {
222
+ return new Promise((resolve, reject) => {
223
+ const image = new Image();
224
+ image.onload = () => resolve(image);
225
+ image.onerror = () => reject(new Error('Unable to load a region capture.'));
226
+ image.src = url;
227
+ });
228
+ }
229
+
230
+ export function multiRegionCaptureProvider(regions: readonly AuthorRegionDraft[]): AuthorCaptureProvider {
231
+ return {
232
+ async capture(signal) {
233
+ throwIfAborted(signal);
234
+ if (regions.length === 0 || regions.length > 16) throw new Error('Capture requires between 1 and 16 regions.');
235
+ const tiles = [];
236
+ for (const region of regions) {
237
+ const image = region.thumbnailUrl === undefined ? undefined : await loadImage(region.thumbnailUrl);
238
+ throwIfAborted(signal);
239
+ const width = image?.naturalWidth ?? region.viewport.width;
240
+ const height = image?.naturalHeight ?? region.viewport.height;
241
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
242
+ throw new Error('Image is not ready to capture');
243
+ }
244
+ tiles.push({ region, image, width, height });
245
+ }
246
+ const width = Math.min(AUTHOR_CAPTURE_MAX_DIMENSION, Math.max(...tiles.map((tile) => tile.width)));
247
+ const naturalHeight = tiles.reduce((height, tile) => height + (tile.height * width) / tile.width, 0);
248
+ const scale = Math.min(1, AUTHOR_CAPTURE_MAX_DIMENSION / Math.max(width, naturalHeight));
249
+ const canvas = document.createElement('canvas');
250
+ canvas.width = Math.max(1, Math.round(width * scale));
251
+ canvas.height = Math.max(1, Math.round(naturalHeight * scale));
252
+ const context = canvas.getContext('2d');
253
+ if (context === null) throw new Error('Canvas is unavailable');
254
+ context.scale(scale, scale);
255
+ context.fillStyle = '#101216';
256
+ context.fillRect(0, 0, width, naturalHeight);
257
+ let y = 0;
258
+ for (const [index, { region, image, width: sourceWidth, height: sourceHeight }] of tiles.entries()) {
259
+ const annotationColor = AUTHOR_REGION_COLORS[index % AUTHOR_REGION_COLORS.length]!;
260
+ throwIfAborted(signal);
261
+ const tileHeight = (sourceHeight * width) / sourceWidth;
262
+ const drawWidth = width;
263
+ const drawHeight = tileHeight;
264
+ const drawX = 0;
265
+ const drawY = y;
266
+ let labelX = drawX;
267
+ let labelY = drawY;
268
+ if (image !== undefined) {
269
+ context.drawImage(image, drawX, drawY, drawWidth, drawHeight);
270
+ if ('rect' in region.anchor) {
271
+ const rect = region.anchor.rect;
272
+ const rx = drawX + rect.x * drawWidth;
273
+ const ry = drawY + rect.y * drawHeight;
274
+ const rw = rect.width * drawWidth;
275
+ const rh = rect.height * drawHeight;
276
+ context.fillStyle = 'rgba(8,10,13,0.62)';
277
+ context.fillRect(drawX, drawY, drawWidth, Math.max(0, ry - drawY));
278
+ context.fillRect(drawX, ry + rh, drawWidth, Math.max(0, drawY + drawHeight - ry - rh));
279
+ context.fillRect(drawX, ry, Math.max(0, rx - drawX), rh);
280
+ context.fillRect(rx + rw, ry, Math.max(0, drawX + drawWidth - rx - rw), rh);
281
+ context.strokeStyle = annotationColor;
282
+ context.lineWidth = 3;
283
+ context.strokeRect(rx, ry, rw, rh);
284
+ labelX = rx;
285
+ labelY = ry;
286
+ }
287
+ }
288
+ // Keep ordinals readable after downscaling, but never larger than their image.
289
+ const ordinal = String(index + 1);
290
+ let badgeScale = Math.min(1 / scale, drawHeight / 36);
291
+ context.font = `bold ${String(24 * badgeScale)}px monospace`;
292
+ const measuredWidth = context.measureText(ordinal).width + 12 * badgeScale;
293
+ if (measuredWidth > drawWidth) badgeScale *= drawWidth / measuredWidth;
294
+ context.font = `bold ${String(24 * badgeScale)}px monospace`;
295
+ context.textBaseline = 'top';
296
+ const padding = 6 * badgeScale;
297
+ const labelWidth = Math.min(drawWidth, context.measureText(ordinal).width + padding * 2);
298
+ const labelHeight = 36 * badgeScale;
299
+ labelX = Math.max(drawX, Math.min(labelX, drawX + drawWidth - labelWidth));
300
+ labelY = Math.max(drawY, Math.min(labelY, drawY + drawHeight - labelHeight));
301
+ context.fillStyle = annotationColor;
302
+ context.fillRect(labelX, labelY, labelWidth, labelHeight);
303
+ context.fillStyle = annotationForeground(annotationColor);
304
+ context.fillText(ordinal, labelX + padding, labelY + padding);
305
+ y += tileHeight;
306
+ }
307
+ throwIfAborted(signal);
308
+ return boundedCanvasCapture(canvas);
309
+ },
310
+ };
311
+ }
312
+
313
+ export async function attachAuthorCapture(
314
+ provider: AuthorCaptureProvider,
315
+ context: WebPluginContextItem,
316
+ attach: (capture: ComposerCapture) => void,
317
+ signal?: AbortSignal,
318
+ ): Promise<void> {
319
+ const capture = await provider.capture(signal);
320
+ throwIfAborted(signal);
321
+ attach({ ...capture, context });
322
+ }
@@ -0,0 +1,316 @@
1
+ import type { AuthorJsonSchema } from '../../types/author.ts';
2
+ import { authorGridGeometry, resolveAuthorGridCell, resolveAuthorGridNativeAnchor } from '../lib/authorGrid.ts';
3
+ import type {
4
+ AuthorDocumentKind,
5
+ AuthorNativeAnchor,
6
+ AuthorRegionDraft,
7
+ AuthorTrustedTool,
8
+ } from '../lib/authorViewportTypes.ts';
9
+ import {
10
+ addAuthorRegion,
11
+ authorDocument,
12
+ authorSessionWorkspace,
13
+ putAuthorRequest,
14
+ reviseAuthorDocument,
15
+ reviseAuthorFragment,
16
+ setAuthorCrop,
17
+ updateAuthorRequest,
18
+ } from './authorWorkspaceStore.ts';
19
+
20
+ const stringProperty = { type: 'string', minLength: 1 } as const;
21
+
22
+ function inputRecord(input: unknown): Record<string, unknown> {
23
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) throw new Error('Expected an object.');
24
+ return input as Record<string, unknown>;
25
+ }
26
+
27
+ function requiredString(value: Record<string, unknown>, name: string): string {
28
+ if (typeof value[name] !== 'string' || value[name] === '') throw new Error(`${name} must be a non-empty string.`);
29
+ return value[name];
30
+ }
31
+
32
+ function resolvedAnchor(
33
+ sessionId: string,
34
+ path: string,
35
+ kind: AuthorDocumentKind,
36
+ cell: ReturnType<typeof resolveAuthorGridCell>,
37
+ ): { anchor: AuthorNativeAnchor; quote?: string } {
38
+ const document = authorDocument(sessionId, path);
39
+ if (document === undefined) throw new Error('STALE_DOCUMENT: The focused Author document is no longer open.');
40
+ if (kind === 'pdf' || kind === 'video' || kind === 'opaque') {
41
+ throw new Error(
42
+ 'UNSUPPORTED_GRID: PDF and video coordinates are capture-only and require a visible native selection.',
43
+ );
44
+ }
45
+ return resolveAuthorGridNativeAnchor(sessionId, cell);
46
+ }
47
+
48
+ function checkedRegion(sessionId: string, path: string, value: Record<string, unknown>) {
49
+ const document = authorDocument(sessionId, path);
50
+ if (document === undefined) throw new Error('STALE_DOCUMENT: The Author document is no longer open.');
51
+ if (document.savingVersion !== undefined)
52
+ throw new Error('SAVE_IN_PROGRESS: Wait for the current Author save to finish.');
53
+ const expectedRevision = value.expectedRevision;
54
+ const expectedSourceSha256 = requiredString(value, 'expectedSourceSha256');
55
+ if (expectedRevision !== document.version || expectedSourceSha256 !== document.sourceSha256) {
56
+ throw new Error('STALE_DOCUMENT: The Author revision or source digest changed.');
57
+ }
58
+ const regionId = requiredString(value, 'regionId');
59
+ const workspace = authorSessionWorkspace(sessionId);
60
+ const region =
61
+ workspace.regions.find((candidate) => candidate.id === regionId) ??
62
+ workspace.requests
63
+ .filter((request) => request.status === 'REQUESTED' || request.status === 'CHANGING')
64
+ .flatMap((request) => request.pendingRegions ?? request.regions)
65
+ .find((candidate) => candidate.id === regionId);
66
+ if (region === undefined || region.documentPath !== path)
67
+ throw new Error('STALE_REGION: The resolved Author region is unavailable.');
68
+ if (region.revision !== document.version || region.sourceSha256 !== document.sourceSha256) {
69
+ throw new Error('STALE_REGION: The resolved Author region no longer matches the document.');
70
+ }
71
+ return { document, region };
72
+ }
73
+
74
+ function gridTools(sessionId: string, path: string, kind: AuthorDocumentKind): AuthorTrustedTool[] {
75
+ const describeSchema: AuthorJsonSchema = { type: 'object', additionalProperties: false, properties: {} };
76
+ return [
77
+ {
78
+ name: 'author_describe_grid',
79
+ label: 'Describe grid',
80
+ description: 'Describe the current A1 through H8 grid and return its geometry token.',
81
+ inputSchema: describeSchema,
82
+ execute: async () => {
83
+ const geometry = authorGridGeometry(sessionId);
84
+ const document = authorDocument(sessionId, path);
85
+ if (
86
+ geometry === undefined ||
87
+ document === undefined ||
88
+ geometry.documentPath !== path ||
89
+ geometry.revision !== document.version
90
+ ) {
91
+ throw new Error('STALE_GRID: The visible Author grid is unavailable.');
92
+ }
93
+ return { columns: 'A-H', rows: '1-8', ...geometry };
94
+ },
95
+ },
96
+ {
97
+ name: 'author_resolve_grid_cell',
98
+ label: 'Resolve grid cell',
99
+ description: 'Resolve one current grid cell to a native document anchor before mutation.',
100
+ inputSchema: {
101
+ type: 'object',
102
+ additionalProperties: false,
103
+ required: ['cell', 'geometryToken', 'instruction'],
104
+ properties: { cell: stringProperty, geometryToken: stringProperty, instruction: stringProperty },
105
+ },
106
+ execute: async (input) => {
107
+ const value = inputRecord(input);
108
+ const instruction = requiredString(value, 'instruction');
109
+ const cell = resolveAuthorGridCell(
110
+ sessionId,
111
+ requiredString(value, 'cell'),
112
+ requiredString(value, 'geometryToken'),
113
+ );
114
+ const geometry = authorGridGeometry(sessionId)!;
115
+ const resolved = resolvedAnchor(sessionId, path, kind, cell);
116
+ const regionId = crypto.randomUUID();
117
+ const createdAt = Date.now();
118
+ const region = {
119
+ id: regionId,
120
+ documentPath: path,
121
+ revision: geometry.revision,
122
+ sourceSha256: geometry.sourceSha256,
123
+ comment: instruction,
124
+ ...resolved,
125
+ viewport: { ...geometry.viewport },
126
+ voiceGrid: cell.evidence,
127
+ createdAt,
128
+ };
129
+ addAuthorRegion(sessionId, region);
130
+ putAuthorRequest(sessionId, {
131
+ id: `voice:${regionId}`,
132
+ documentPath: path,
133
+ requestText: instruction,
134
+ regions: [region],
135
+ pendingRegions: [region],
136
+ status: 'REQUESTED',
137
+ createdAt,
138
+ updatedAt: createdAt,
139
+ revision: geometry.revision,
140
+ sourceSha256: geometry.sourceSha256,
141
+ });
142
+ return { regionId, anchor: resolved.anchor, quote: resolved.quote, evidence: cell.evidence };
143
+ },
144
+ },
145
+ ];
146
+ }
147
+
148
+ interface MutationResult {
149
+ changed: true;
150
+ before?: string;
151
+ after?: string;
152
+ crop?: unknown;
153
+ revision: number;
154
+ }
155
+
156
+ function assertRebasable(pending: readonly AuthorRegionDraft[], changed: AuthorRegionDraft): void {
157
+ const remaining = pending.filter((region) => region.id !== changed.id);
158
+ if (changed.anchor.kind === 'image-rect' && remaining.length > 0)
159
+ throw new Error('UNSUPPORTED_REGION: A multi-region image request cannot apply more than one crop.');
160
+ if (changed.anchor.kind !== 'text-range') return;
161
+ for (const region of remaining) {
162
+ if (region.anchor.kind !== 'text-range') continue;
163
+ const separate =
164
+ region.anchor.endOffset <= changed.anchor.startOffset || region.anchor.startOffset >= changed.anchor.endOffset;
165
+ if (!separate) throw new Error('AMBIGUOUS_REGION: Submitted text regions overlap and cannot be safely rebased.');
166
+ }
167
+ }
168
+
169
+ function lineAtOffset(content: string, offset: number): number {
170
+ return content.slice(0, Math.max(0, offset)).split('\n').length;
171
+ }
172
+
173
+ function rebasePendingRegions(
174
+ pending: readonly AuthorRegionDraft[],
175
+ changed: AuthorRegionDraft,
176
+ result: MutationResult,
177
+ nextContent: string | undefined,
178
+ ): readonly AuthorRegionDraft[] {
179
+ return pending
180
+ .filter((region) => region.id !== changed.id)
181
+ .map((region) => {
182
+ if (changed.anchor.kind !== 'text-range' || region.anchor.kind !== 'text-range' || nextContent === undefined)
183
+ return { ...region, revision: result.revision };
184
+ const delta = (result.after?.length ?? 0) - (result.before?.length ?? 0);
185
+ const shift = region.anchor.startOffset >= changed.anchor.endOffset ? delta : 0;
186
+ const startOffset = region.anchor.startOffset + shift;
187
+ const endOffset = region.anchor.endOffset + shift;
188
+ return {
189
+ ...region,
190
+ revision: result.revision,
191
+ anchor: {
192
+ ...region.anchor,
193
+ startOffset,
194
+ endOffset,
195
+ startLine: lineAtOffset(nextContent, startOffset),
196
+ endLine: lineAtOffset(nextContent, endOffset),
197
+ },
198
+ };
199
+ });
200
+ }
201
+ function mutationTool(sessionId: string, path: string, kind: AuthorDocumentKind): AuthorTrustedTool | undefined {
202
+ if (kind === 'pdf' || kind === 'video' || kind === 'opaque') return undefined;
203
+ const needsReplacement = kind !== 'image';
204
+ return {
205
+ name: 'author_apply_region',
206
+ label: 'Apply region change',
207
+ description: 'Apply a fenced mutation through a previously resolved native Author region.',
208
+ inputSchema: {
209
+ type: 'object',
210
+ additionalProperties: false,
211
+ required: ['regionId', 'expectedRevision', 'expectedSourceSha256', ...(needsReplacement ? ['replacement'] : [])],
212
+ properties: {
213
+ regionId: stringProperty,
214
+ expectedRevision: { type: 'integer', minimum: 0 },
215
+ expectedSourceSha256: stringProperty,
216
+ ...(needsReplacement ? { replacement: { type: 'string' } } : {}),
217
+ },
218
+ },
219
+ execute: async (input, signal) => {
220
+ const value = inputRecord(input);
221
+ const regionId = requiredString(value, 'regionId');
222
+ const request = authorSessionWorkspace(sessionId).requests.find(
223
+ (candidate) =>
224
+ (candidate.pendingRegions ?? candidate.regions).some((item) => item.id === regionId) &&
225
+ candidate.status === 'REQUESTED',
226
+ );
227
+ if (request !== undefined) {
228
+ updateAuthorRequest(sessionId, request.id, (current) => ({
229
+ ...current,
230
+ status: 'CHANGING',
231
+ currentOperation: 'validating native anchor',
232
+ updatedAt: Date.now(),
233
+ }));
234
+ }
235
+ try {
236
+ if (signal.aborted)
237
+ throw signal.reason instanceof Error ? signal.reason : new Error('Author mutation cancelled.');
238
+ const { document, region } = checkedRegion(sessionId, path, value);
239
+ const pending = request?.pendingRegions ?? request?.regions ?? [region];
240
+ assertRebasable(pending, region);
241
+ if (request !== undefined) {
242
+ updateAuthorRequest(sessionId, request.id, (current) => ({
243
+ ...current,
244
+ currentOperation: `mutating ${region.anchor.kind}`,
245
+ updatedAt: Date.now(),
246
+ }));
247
+ }
248
+ let result: MutationResult;
249
+ let nextContent: string | undefined;
250
+ if (region.anchor.kind === 'text-range') {
251
+ const replacement = typeof value.replacement === 'string' ? value.replacement : '';
252
+ const { startOffset, endOffset } = region.anchor;
253
+ const content = document.content ?? '';
254
+ const before = content.slice(startOffset, endOffset);
255
+ nextContent = content.slice(0, startOffset) + replacement + content.slice(endOffset);
256
+ reviseAuthorDocument(sessionId, path, nextContent);
257
+ result = { changed: true, before, after: replacement, revision: document.version + 1 };
258
+ } else if (region.anchor.kind === 'cell' || region.anchor.kind === 'slide-element') {
259
+ const fragmentId = region.anchor.fragmentId;
260
+ const fragment = document.fragments?.find((candidate) => candidate.id === fragmentId);
261
+ if (fragment === undefined || fragment.readOnly === true)
262
+ throw new Error('UNSUPPORTED_REGION: The native fragment is not editable.');
263
+ const replacement = typeof value.replacement === 'string' ? value.replacement : '';
264
+ reviseAuthorFragment(sessionId, path, fragment.id, replacement);
265
+ result = { changed: true, before: fragment.text, after: replacement, revision: document.version + 1 };
266
+ } else if (region.anchor.kind === 'image-rect') {
267
+ setAuthorCrop(sessionId, path, region.anchor.rect);
268
+ result = { changed: true, crop: region.anchor.rect, revision: document.version + 1 };
269
+ } else {
270
+ throw new Error('UNSUPPORTED_REGION: PDF and video regions are capture-only.');
271
+ }
272
+ if (request !== undefined) {
273
+ const pendingRegions = rebasePendingRegions(pending, region, result, nextContent);
274
+ updateAuthorRequest(sessionId, request.id, (current) => ({
275
+ ...current,
276
+ status: pendingRegions.length === 0 ? 'CHANGED' : 'REQUESTED',
277
+ currentOperation: undefined,
278
+ before: [current.before, result.before].filter((item) => item !== undefined).join('\n') || undefined,
279
+ after:
280
+ [current.after, result.after ?? (result.crop === undefined ? undefined : JSON.stringify(result.crop))]
281
+ .filter((item) => item !== undefined)
282
+ .join('\n') || undefined,
283
+ pendingRegions,
284
+ revision: result.revision,
285
+ updatedAt: Date.now(),
286
+ }));
287
+ }
288
+ return result;
289
+ } catch (error) {
290
+ if (request !== undefined) {
291
+ updateAuthorRequest(sessionId, request.id, (current) => ({
292
+ ...current,
293
+ status: signal.aborted ? 'CANCELLED' : 'FAILED',
294
+ currentOperation: undefined,
295
+ error: signal.aborted
296
+ ? 'Author mutation cancelled.'
297
+ : error instanceof Error
298
+ ? error.message
299
+ : String(error),
300
+ updatedAt: Date.now(),
301
+ }));
302
+ }
303
+ throw error;
304
+ }
305
+ },
306
+ };
307
+ }
308
+
309
+ export function authorGridTools(
310
+ sessionId: string,
311
+ path: string,
312
+ kind: AuthorDocumentKind,
313
+ ): readonly AuthorTrustedTool[] {
314
+ const mutation = mutationTool(sessionId, path, kind);
315
+ return [...gridTools(sessionId, path, kind), ...(mutation === undefined ? [] : [mutation])];
316
+ }