@amaster.ai/pi-lark 0.1.3 → 0.1.5

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 (404) hide show
  1. package/package.json +3 -3
  2. package/skills/lark-approval/SKILL.md +99 -0
  3. package/skills/lark-approval/references/lark-approval-approvals-get.md +128 -0
  4. package/skills/lark-approval/references/lark-approval-approvals-search.md +103 -0
  5. package/skills/lark-approval/references/lark-approval-initiate.md +224 -0
  6. package/skills/lark-approval/references/lark-approval-instance-form-control-parameters.md +606 -0
  7. package/skills/lark-approval/references/lark-approval-instance-value-sourcing.md +108 -0
  8. package/skills/lark-approval/references/lark-approval-instances-cancel.md +78 -0
  9. package/skills/lark-approval/references/lark-approval-instances-cc.md +105 -0
  10. package/skills/lark-approval/references/lark-approval-instances-get.md +145 -0
  11. package/skills/lark-approval/references/lark-approval-instances-initiated.md +122 -0
  12. package/skills/lark-approval/references/lark-approval-tasks-add-sign.md +120 -0
  13. package/skills/lark-approval/references/lark-approval-tasks-approve.md +81 -0
  14. package/skills/lark-approval/references/lark-approval-tasks-query.md +76 -0
  15. package/skills/lark-approval/references/lark-approval-tasks-reject.md +73 -0
  16. package/skills/lark-approval/references/lark-approval-tasks-remind.md +82 -0
  17. package/skills/lark-approval/references/lark-approval-tasks-rollback.md +83 -0
  18. package/skills/lark-approval/references/lark-approval-tasks-transfer.md +91 -0
  19. package/skills/lark-apps/SKILL.md +92 -0
  20. package/skills/lark-apps/references/lark-apps-access-scope-get.md +28 -0
  21. package/skills/lark-apps/references/lark-apps-access-scope-set.md +40 -0
  22. package/skills/lark-apps/references/lark-apps-cloud-dev.md +120 -0
  23. package/skills/lark-apps/references/lark-apps-create.md +40 -0
  24. package/skills/lark-apps/references/lark-apps-db-execute.md +44 -0
  25. package/skills/lark-apps/references/lark-apps-db.md +162 -0
  26. package/skills/lark-apps/references/lark-apps-env-pull.md +37 -0
  27. package/skills/lark-apps/references/lark-apps-env.md +48 -0
  28. package/skills/lark-apps/references/lark-apps-file.md +96 -0
  29. package/skills/lark-apps/references/lark-apps-git-credential.md +37 -0
  30. package/skills/lark-apps/references/lark-apps-html-publish.md +57 -0
  31. package/skills/lark-apps/references/lark-apps-init.md +37 -0
  32. package/skills/lark-apps/references/lark-apps-list.md +37 -0
  33. package/skills/lark-apps/references/lark-apps-local-dev.md +78 -0
  34. package/skills/lark-apps/references/lark-apps-observability.md +48 -0
  35. package/skills/lark-apps/references/lark-apps-openapi-key.md +79 -0
  36. package/skills/lark-apps/references/lark-apps-plugin-install.md +36 -0
  37. package/skills/lark-apps/references/lark-apps-plugin-list.md +23 -0
  38. package/skills/lark-apps/references/lark-apps-plugin-uninstall.md +25 -0
  39. package/skills/lark-apps/references/lark-apps-release-create.md +30 -0
  40. package/skills/lark-apps/references/lark-apps-release-get.md +28 -0
  41. package/skills/lark-apps/references/lark-apps-release-list.md +31 -0
  42. package/skills/lark-apps/references/lark-apps-session-messages-list.md +53 -0
  43. package/skills/lark-apps/references/lark-apps-update.md +30 -0
  44. package/skills/lark-attendance/SKILL.md +57 -0
  45. package/skills/lark-base/SKILL.md +157 -0
  46. package/skills/lark-base/references/dashboard-block-data-config.md +350 -0
  47. package/skills/lark-base/references/formula-field-guide.md +737 -0
  48. package/skills/lark-base/references/lark-base-cell-value.md +153 -0
  49. package/skills/lark-base/references/lark-base-dashboard-block-get-data.md +717 -0
  50. package/skills/lark-base/references/lark-base-dashboard.md +238 -0
  51. package/skills/lark-base/references/lark-base-data-analysis-sop.md +210 -0
  52. package/skills/lark-base/references/lark-base-data-query-guide.md +61 -0
  53. package/skills/lark-base/references/lark-base-data-query.md +452 -0
  54. package/skills/lark-base/references/lark-base-field-create.md +103 -0
  55. package/skills/lark-base/references/lark-base-field-json.md +490 -0
  56. package/skills/lark-base/references/lark-base-field-update.md +171 -0
  57. package/skills/lark-base/references/lark-base-form-detail.md +71 -0
  58. package/skills/lark-base/references/lark-base-form-questions-create.md +118 -0
  59. package/skills/lark-base/references/lark-base-form-questions-update.md +92 -0
  60. package/skills/lark-base/references/lark-base-form-submit.md +170 -0
  61. package/skills/lark-base/references/lark-base-record-batch-create.md +57 -0
  62. package/skills/lark-base/references/lark-base-record-batch-update.md +52 -0
  63. package/skills/lark-base/references/lark-base-record-history-list.md +43 -0
  64. package/skills/lark-base/references/lark-base-record-upsert.md +63 -0
  65. package/skills/lark-base/references/lark-base-role-guide.md +65 -0
  66. package/skills/lark-base/references/lark-base-view-set-filter.md +189 -0
  67. package/skills/lark-base/references/lark-base-workflow-guide.md +830 -0
  68. package/skills/lark-base/references/lark-base-workflow-schema.md +1071 -0
  69. package/skills/lark-base/references/lookup-field-guide.md +512 -0
  70. package/skills/lark-base/references/role-config.md +549 -0
  71. package/skills/lark-calendar/SKILL.md +140 -0
  72. package/skills/lark-calendar/references/lark-calendar-agenda.md +78 -0
  73. package/skills/lark-calendar/references/lark-calendar-create.md +114 -0
  74. package/skills/lark-calendar/references/lark-calendar-freebusy.md +124 -0
  75. package/skills/lark-calendar/references/lark-calendar-meeting.md +40 -0
  76. package/skills/lark-calendar/references/lark-calendar-recurring.md +90 -0
  77. package/skills/lark-calendar/references/lark-calendar-room-find.md +113 -0
  78. package/skills/lark-calendar/references/lark-calendar-rsvp.md +42 -0
  79. package/skills/lark-calendar/references/lark-calendar-schedule-meeting.md +265 -0
  80. package/skills/lark-calendar/references/lark-calendar-search-event.md +29 -0
  81. package/skills/lark-calendar/references/lark-calendar-suggestion.md +125 -0
  82. package/skills/lark-calendar/references/lark-calendar-update.md +105 -0
  83. package/skills/lark-contact/SKILL.md +55 -0
  84. package/skills/lark-contact/references/lark-contact-get-user.md +19 -0
  85. package/skills/lark-contact/references/lark-contact-search-user.md +123 -0
  86. package/skills/lark-doc/SKILL.md +84 -0
  87. package/skills/lark-doc/references/lark-doc-create.md +80 -0
  88. package/skills/lark-doc/references/lark-doc-fetch.md +138 -0
  89. package/skills/lark-doc/references/lark-doc-history.md +107 -0
  90. package/skills/lark-doc/references/lark-doc-md.md +76 -0
  91. package/skills/lark-doc/references/lark-doc-media-download.md +50 -0
  92. package/skills/lark-doc/references/lark-doc-media-insert.md +114 -0
  93. package/skills/lark-doc/references/lark-doc-media-preview.md +41 -0
  94. package/skills/lark-doc/references/lark-doc-mindnote.md +113 -0
  95. package/skills/lark-doc/references/lark-doc-resource-cover.md +70 -0
  96. package/skills/lark-doc/references/lark-doc-update.md +260 -0
  97. package/skills/lark-doc/references/lark-doc-whiteboard.md +154 -0
  98. package/skills/lark-doc/references/lark-doc-word-stat.md +93 -0
  99. package/skills/lark-doc/references/lark-doc-xml.md +181 -0
  100. package/skills/lark-doc/references/style/lark-doc-create-workflow.md +47 -0
  101. package/skills/lark-doc/references/style/lark-doc-style.md +68 -0
  102. package/skills/lark-doc/references/style/lark-doc-update-workflow.md +48 -0
  103. package/skills/lark-doc/scripts/doc_word_stat.py +1243 -0
  104. package/skills/lark-drive/SKILL.md +220 -0
  105. package/skills/lark-drive/references/lark-drive-add-comment.md +193 -0
  106. package/skills/lark-drive/references/lark-drive-apply-permission.md +77 -0
  107. package/skills/lark-drive/references/lark-drive-comment-location.md +193 -0
  108. package/skills/lark-drive/references/lark-drive-comments-guide.md +72 -0
  109. package/skills/lark-drive/references/lark-drive-cover.md +79 -0
  110. package/skills/lark-drive/references/lark-drive-create-folder.md +73 -0
  111. package/skills/lark-drive/references/lark-drive-create-shortcut.md +103 -0
  112. package/skills/lark-drive/references/lark-drive-delete.md +79 -0
  113. package/skills/lark-drive/references/lark-drive-download.md +31 -0
  114. package/skills/lark-drive/references/lark-drive-export-download.md +50 -0
  115. package/skills/lark-drive/references/lark-drive-export.md +145 -0
  116. package/skills/lark-drive/references/lark-drive-files-list.md +158 -0
  117. package/skills/lark-drive/references/lark-drive-import.md +178 -0
  118. package/skills/lark-drive/references/lark-drive-inspect.md +50 -0
  119. package/skills/lark-drive/references/lark-drive-member-add.md +66 -0
  120. package/skills/lark-drive/references/lark-drive-move.md +120 -0
  121. package/skills/lark-drive/references/lark-drive-permission-guide.md +41 -0
  122. package/skills/lark-drive/references/lark-drive-preview.md +87 -0
  123. package/skills/lark-drive/references/lark-drive-pull.md +137 -0
  124. package/skills/lark-drive/references/lark-drive-push.md +162 -0
  125. package/skills/lark-drive/references/lark-drive-reactions.md +113 -0
  126. package/skills/lark-drive/references/lark-drive-search.md +273 -0
  127. package/skills/lark-drive/references/lark-drive-secure-label.md +52 -0
  128. package/skills/lark-drive/references/lark-drive-status.md +137 -0
  129. package/skills/lark-drive/references/lark-drive-task-result.md +302 -0
  130. package/skills/lark-drive/references/lark-drive-upload.md +101 -0
  131. package/skills/lark-drive/references/lark-drive-version-delete.md +38 -0
  132. package/skills/lark-drive/references/lark-drive-version-get.md +71 -0
  133. package/skills/lark-drive/references/lark-drive-version-history.md +73 -0
  134. package/skills/lark-drive/references/lark-drive-version-revert.md +35 -0
  135. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-analysis.md +249 -0
  136. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-discovery.md +253 -0
  137. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-execution.md +200 -0
  138. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-planning.md +336 -0
  139. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-rollback.md +308 -0
  140. package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize.md +226 -0
  141. package/skills/lark-drive/references/lark-drive-workflow-permission-governance-commands.md +168 -0
  142. package/skills/lark-drive/references/lark-drive-workflow-permission-governance-outputs.md +424 -0
  143. package/skills/lark-drive/references/lark-drive-workflow-permission-governance.md +207 -0
  144. package/skills/lark-drive/references/lark-drive-workflow.md +130 -0
  145. package/skills/lark-event/SKILL.md +154 -0
  146. package/skills/lark-event/references/lark-event-im.md +87 -0
  147. package/skills/lark-event/references/lark-event-minutes.md +54 -0
  148. package/skills/lark-event/references/lark-event-task.md +78 -0
  149. package/skills/lark-event/references/lark-event-vc.md +106 -0
  150. package/skills/lark-event/references/lark-event-whiteboard.md +67 -0
  151. package/skills/lark-im/SKILL.md +248 -0
  152. package/skills/lark-im/references/card/card-2.0-schema.md +107 -0
  153. package/skills/lark-im/references/card/components/button.md +63 -0
  154. package/skills/lark-im/references/card/components/chart.md +57 -0
  155. package/skills/lark-im/references/card/components/checker.md +38 -0
  156. package/skills/lark-im/references/card/components/collapsible_panel.md +46 -0
  157. package/skills/lark-im/references/card/components/column_set.md +53 -0
  158. package/skills/lark-im/references/card/components/date_picker.md +34 -0
  159. package/skills/lark-im/references/card/components/div.md +36 -0
  160. package/skills/lark-im/references/card/components/form.md +51 -0
  161. package/skills/lark-im/references/card/components/header.md +34 -0
  162. package/skills/lark-im/references/card/components/hr.md +17 -0
  163. package/skills/lark-im/references/card/components/img.md +34 -0
  164. package/skills/lark-im/references/card/components/img_combination.md +30 -0
  165. package/skills/lark-im/references/card/components/input.md +43 -0
  166. package/skills/lark-im/references/card/components/interactive_container.md +46 -0
  167. package/skills/lark-im/references/card/components/markdown.md +56 -0
  168. package/skills/lark-im/references/card/components/multi_select_person.md +40 -0
  169. package/skills/lark-im/references/card/components/multi_select_static.md +40 -0
  170. package/skills/lark-im/references/card/components/overflow.md +36 -0
  171. package/skills/lark-im/references/card/components/person.md +30 -0
  172. package/skills/lark-im/references/card/components/person_list.md +31 -0
  173. package/skills/lark-im/references/card/components/picker_datetime.md +34 -0
  174. package/skills/lark-im/references/card/components/picker_time.md +34 -0
  175. package/skills/lark-im/references/card/components/recycling_container.md +35 -0
  176. package/skills/lark-im/references/card/components/select_img.md +42 -0
  177. package/skills/lark-im/references/card/components/select_person.md +39 -0
  178. package/skills/lark-im/references/card/components/select_static.md +43 -0
  179. package/skills/lark-im/references/card/components/table.md +53 -0
  180. package/skills/lark-im/references/card/lark-im-card-create.md +180 -0
  181. package/skills/lark-im/references/card/lark-im-card-style.md +281 -0
  182. package/skills/lark-im/references/card/resource/colors.md +34 -0
  183. package/skills/lark-im/references/card/resource/icons.md +38 -0
  184. package/skills/lark-im/references/lark-im-card-action-reply.md +175 -0
  185. package/skills/lark-im/references/lark-im-chat-create.md +162 -0
  186. package/skills/lark-im/references/lark-im-chat-identity.md +55 -0
  187. package/skills/lark-im/references/lark-im-chat-list.md +166 -0
  188. package/skills/lark-im/references/lark-im-chat-members-list.md +83 -0
  189. package/skills/lark-im/references/lark-im-chat-messages-list.md +157 -0
  190. package/skills/lark-im/references/lark-im-chat-search.md +142 -0
  191. package/skills/lark-im/references/lark-im-chat-update.md +84 -0
  192. package/skills/lark-im/references/lark-im-feed-group-list-item.md +68 -0
  193. package/skills/lark-im/references/lark-im-feed-group-list.md +65 -0
  194. package/skills/lark-im/references/lark-im-feed-group-query-item.md +44 -0
  195. package/skills/lark-im/references/lark-im-feed-groups.md +452 -0
  196. package/skills/lark-im/references/lark-im-feed-shortcut-create.md +97 -0
  197. package/skills/lark-im/references/lark-im-feed-shortcut-list.md +103 -0
  198. package/skills/lark-im/references/lark-im-feed-shortcut-remove.md +48 -0
  199. package/skills/lark-im/references/lark-im-flag-cancel.md +67 -0
  200. package/skills/lark-im/references/lark-im-flag-create.md +67 -0
  201. package/skills/lark-im/references/lark-im-flag-list.md +100 -0
  202. package/skills/lark-im/references/lark-im-message-enrichment.md +54 -0
  203. package/skills/lark-im/references/lark-im-messages-mget.md +99 -0
  204. package/skills/lark-im/references/lark-im-messages-reply.md +277 -0
  205. package/skills/lark-im/references/lark-im-messages-resources-download.md +94 -0
  206. package/skills/lark-im/references/lark-im-messages-search.md +234 -0
  207. package/skills/lark-im/references/lark-im-messages-send.md +279 -0
  208. package/skills/lark-im/references/lark-im-reactions.md +299 -0
  209. package/skills/lark-im/references/lark-im-threads-messages-list.md +115 -0
  210. package/skills/lark-mail/SKILL.md +287 -0
  211. package/skills/lark-mail/assets/templates/job-application--resume.html +33 -0
  212. package/skills/lark-mail/assets/templates/newsletter--weekly-brief.html +50 -0
  213. package/skills/lark-mail/assets/templates/research--market-report.html +256 -0
  214. package/skills/lark-mail/assets/templates/weekly--personal-report.html +43 -0
  215. package/skills/lark-mail/assets/templates/weekly--team-report.html +9 -0
  216. package/skills/lark-mail/references/lark-mail-calendar-invite.md +36 -0
  217. package/skills/lark-mail/references/lark-mail-decline-receipt.md +115 -0
  218. package/skills/lark-mail/references/lark-mail-draft-create.md +127 -0
  219. package/skills/lark-mail/references/lark-mail-draft-edit.md +404 -0
  220. package/skills/lark-mail/references/lark-mail-forward.md +239 -0
  221. package/skills/lark-mail/references/lark-mail-html.md +333 -0
  222. package/skills/lark-mail/references/lark-mail-lint-html.md +243 -0
  223. package/skills/lark-mail/references/lark-mail-message.md +233 -0
  224. package/skills/lark-mail/references/lark-mail-messages.md +108 -0
  225. package/skills/lark-mail/references/lark-mail-recall.md +66 -0
  226. package/skills/lark-mail/references/lark-mail-recipient-search.md +59 -0
  227. package/skills/lark-mail/references/lark-mail-reply-all.md +213 -0
  228. package/skills/lark-mail/references/lark-mail-reply.md +249 -0
  229. package/skills/lark-mail/references/lark-mail-rules.md +31 -0
  230. package/skills/lark-mail/references/lark-mail-send-as.md +44 -0
  231. package/skills/lark-mail/references/lark-mail-send-receipt.md +120 -0
  232. package/skills/lark-mail/references/lark-mail-send-status.md +46 -0
  233. package/skills/lark-mail/references/lark-mail-send.md +222 -0
  234. package/skills/lark-mail/references/lark-mail-share-to-chat.md +87 -0
  235. package/skills/lark-mail/references/lark-mail-signature.md +98 -0
  236. package/skills/lark-mail/references/lark-mail-template-create.md +129 -0
  237. package/skills/lark-mail/references/lark-mail-template-update.md +150 -0
  238. package/skills/lark-mail/references/lark-mail-template.md +54 -0
  239. package/skills/lark-mail/references/lark-mail-thread.md +111 -0
  240. package/skills/lark-mail/references/lark-mail-triage.md +131 -0
  241. package/skills/lark-mail/references/lark-mail-watch.md +94 -0
  242. package/skills/lark-markdown/SKILL.md +69 -0
  243. package/skills/lark-markdown/references/lark-markdown-create.md +94 -0
  244. package/skills/lark-markdown/references/lark-markdown-diff.md +156 -0
  245. package/skills/lark-markdown/references/lark-markdown-fetch.md +79 -0
  246. package/skills/lark-markdown/references/lark-markdown-overwrite.md +85 -0
  247. package/skills/lark-markdown/references/lark-markdown-patch.md +160 -0
  248. package/skills/lark-minutes/SKILL.md +192 -0
  249. package/skills/lark-minutes/references/lark-minutes-detail.md +62 -0
  250. package/skills/lark-minutes/references/lark-minutes-download.md +137 -0
  251. package/skills/lark-minutes/references/lark-minutes-search.md +204 -0
  252. package/skills/lark-minutes/references/lark-minutes-speaker-replace.md +109 -0
  253. package/skills/lark-minutes/references/lark-minutes-summary.md +122 -0
  254. package/skills/lark-minutes/references/lark-minutes-todo.md +138 -0
  255. package/skills/lark-minutes/references/lark-minutes-update.md +41 -0
  256. package/skills/lark-minutes/references/lark-minutes-upload.md +104 -0
  257. package/skills/lark-note/SKILL.md +94 -0
  258. package/skills/lark-note/references/lark-note-detail.md +26 -0
  259. package/skills/lark-note/references/lark-note-transcript.md +23 -0
  260. package/skills/lark-okr/SKILL.md +122 -0
  261. package/skills/lark-okr/references/lark-okr-alignments.md +180 -0
  262. package/skills/lark-okr/references/lark-okr-batch-create.md +106 -0
  263. package/skills/lark-okr/references/lark-okr-contentblock.md +427 -0
  264. package/skills/lark-okr/references/lark-okr-cycle-detail.md +91 -0
  265. package/skills/lark-okr/references/lark-okr-cycle-list.md +93 -0
  266. package/skills/lark-okr/references/lark-okr-entities.md +329 -0
  267. package/skills/lark-okr/references/lark-okr-image-upload.md +116 -0
  268. package/skills/lark-okr/references/lark-okr-indicator-update.md +80 -0
  269. package/skills/lark-okr/references/lark-okr-indicators.md +223 -0
  270. package/skills/lark-okr/references/lark-okr-patch.md +104 -0
  271. package/skills/lark-okr/references/lark-okr-progress-create.md +85 -0
  272. package/skills/lark-okr/references/lark-okr-progress-delete.md +47 -0
  273. package/skills/lark-okr/references/lark-okr-progress-get.md +93 -0
  274. package/skills/lark-okr/references/lark-okr-progress-list.md +80 -0
  275. package/skills/lark-okr/references/lark-okr-progress-update.md +85 -0
  276. package/skills/lark-okr/references/lark-okr-reorder.md +81 -0
  277. package/skills/lark-okr/references/lark-okr-weight.md +96 -0
  278. package/skills/lark-openapi-explorer/SKILL.md +153 -0
  279. package/skills/lark-shared/SKILL.md +193 -0
  280. package/skills/lark-shared/references/lark-wiki-token-routing.md +42 -0
  281. package/skills/lark-sheets/SKILL.md +165 -0
  282. package/skills/lark-sheets/references/lark-sheets-batch-update.md +191 -0
  283. package/skills/lark-sheets/references/lark-sheets-chart.md +330 -0
  284. package/skills/lark-sheets/references/lark-sheets-conditional-format.md +179 -0
  285. package/skills/lark-sheets/references/lark-sheets-core-operations.md +103 -0
  286. package/skills/lark-sheets/references/lark-sheets-filter-view.md +137 -0
  287. package/skills/lark-sheets/references/lark-sheets-filter.md +130 -0
  288. package/skills/lark-sheets/references/lark-sheets-float-image.md +159 -0
  289. package/skills/lark-sheets/references/lark-sheets-formula-translation.md +267 -0
  290. package/skills/lark-sheets/references/lark-sheets-pivot-table.md +166 -0
  291. package/skills/lark-sheets/references/lark-sheets-range-operations.md +267 -0
  292. package/skills/lark-sheets/references/lark-sheets-read-data.md +235 -0
  293. package/skills/lark-sheets/references/lark-sheets-search-replace.md +111 -0
  294. package/skills/lark-sheets/references/lark-sheets-sheet-structure.md +212 -0
  295. package/skills/lark-sheets/references/lark-sheets-sparkline.md +149 -0
  296. package/skills/lark-sheets/references/lark-sheets-visual-standards.md +205 -0
  297. package/skills/lark-sheets/references/lark-sheets-workbook.md +395 -0
  298. package/skills/lark-sheets/references/lark-sheets-write-cells.md +565 -0
  299. package/skills/lark-sheets/scripts/sheets_df.py +32 -0
  300. package/skills/lark-skill-maker/SKILL.md +85 -0
  301. package/skills/lark-slides/SKILL.md +274 -0
  302. package/skills/lark-slides/references/asset-planning.md +124 -0
  303. package/skills/lark-slides/references/examples.md +261 -0
  304. package/skills/lark-slides/references/iconpark-index.json +41901 -0
  305. package/skills/lark-slides/references/iconpark.md +46 -0
  306. package/skills/lark-slides/references/lark-slides-create.md +137 -0
  307. package/skills/lark-slides/references/lark-slides-edit-workflows.md +144 -0
  308. package/skills/lark-slides/references/lark-slides-media-upload.md +128 -0
  309. package/skills/lark-slides/references/lark-slides-replace-pages.md +95 -0
  310. package/skills/lark-slides/references/lark-slides-replace-slide.md +240 -0
  311. package/skills/lark-slides/references/lark-slides-screenshot.md +94 -0
  312. package/skills/lark-slides/references/lark-slides-whiteboard.md +330 -0
  313. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md +220 -0
  314. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md +123 -0
  315. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md +110 -0
  316. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-replace.md +187 -0
  317. package/skills/lark-slides/references/lark-slides-xml-presentations-get.md +98 -0
  318. package/skills/lark-slides/references/planning-layer.md +216 -0
  319. package/skills/lark-slides/references/slide-templates.md +201 -0
  320. package/skills/lark-slides/references/slides_demo.xml +226 -0
  321. package/skills/lark-slides/references/slides_xml_schema_definition.xml +3049 -0
  322. package/skills/lark-slides/references/troubleshooting.md +63 -0
  323. package/skills/lark-slides/references/validation-checklist.md +110 -0
  324. package/skills/lark-slides/references/visual-planning.md +254 -0
  325. package/skills/lark-slides/references/xml-format-guide.md +369 -0
  326. package/skills/lark-slides/references/xml-schema-quick-ref.md +245 -0
  327. package/skills/lark-slides/scripts/iconpark_tool.py +362 -0
  328. package/skills/lark-slides/scripts/iconpark_tool_test.py +177 -0
  329. package/skills/lark-slides/scripts/xml_text_overlap_lint.py +367 -0
  330. package/skills/lark-slides/scripts/xml_text_overlap_lint_test.py +299 -0
  331. package/skills/lark-task/SKILL.md +167 -0
  332. package/skills/lark-task/references/lark-task-assign.md +38 -0
  333. package/skills/lark-task/references/lark-task-comment.md +28 -0
  334. package/skills/lark-task/references/lark-task-complete.md +27 -0
  335. package/skills/lark-task/references/lark-task-create.md +57 -0
  336. package/skills/lark-task/references/lark-task-followers.md +35 -0
  337. package/skills/lark-task/references/lark-task-get-my-tasks.md +61 -0
  338. package/skills/lark-task/references/lark-task-get-related-tasks.md +53 -0
  339. package/skills/lark-task/references/lark-task-reminder.md +36 -0
  340. package/skills/lark-task/references/lark-task-reopen.md +27 -0
  341. package/skills/lark-task/references/lark-task-search.md +41 -0
  342. package/skills/lark-task/references/lark-task-set-ancestor.md +32 -0
  343. package/skills/lark-task/references/lark-task-tasklist-create.md +35 -0
  344. package/skills/lark-task/references/lark-task-tasklist-members.md +36 -0
  345. package/skills/lark-task/references/lark-task-tasklist-search.md +38 -0
  346. package/skills/lark-task/references/lark-task-tasklist-task-add.md +38 -0
  347. package/skills/lark-task/references/lark-task-update.md +37 -0
  348. package/skills/lark-task/references/lark-task-upload-attachment.md +59 -0
  349. package/skills/lark-vc/SKILL.md +202 -0
  350. package/skills/lark-vc/references/lark-vc-detail.md +44 -0
  351. package/skills/lark-vc/references/lark-vc-recording.md +154 -0
  352. package/skills/lark-vc/references/lark-vc-search.md +163 -0
  353. package/skills/lark-vc/references/vc-domain-boundaries.md +188 -0
  354. package/skills/lark-vc-agent/SKILL.md +191 -0
  355. package/skills/lark-vc-agent/references/lark-vc-agent-meeting-events.md +287 -0
  356. package/skills/lark-vc-agent/references/lark-vc-agent-meeting-join.md +141 -0
  357. package/skills/lark-vc-agent/references/lark-vc-agent-meeting-leave.md +105 -0
  358. package/skills/lark-vc-agent/references/lark-vc-agent-meeting-list-active.md +91 -0
  359. package/skills/lark-vc-agent/references/lark-vc-agent-meeting-message-send.md +134 -0
  360. package/skills/lark-whiteboard/SKILL.md +47 -0
  361. package/skills/lark-whiteboard/elements/connectors.md +102 -0
  362. package/skills/lark-whiteboard/elements/content.md +40 -0
  363. package/skills/lark-whiteboard/elements/image.md +80 -0
  364. package/skills/lark-whiteboard/elements/layout.md +374 -0
  365. package/skills/lark-whiteboard/elements/schema.md +357 -0
  366. package/skills/lark-whiteboard/elements/style.md +318 -0
  367. package/skills/lark-whiteboard/elements/typography.md +73 -0
  368. package/skills/lark-whiteboard/references/lark-whiteboard-query.md +60 -0
  369. package/skills/lark-whiteboard/references/lark-whiteboard-update.md +122 -0
  370. package/skills/lark-whiteboard/references/lark-whiteboard-workflow.md +94 -0
  371. package/skills/lark-whiteboard/routes/dsl.md +107 -0
  372. package/skills/lark-whiteboard/routes/mermaid.md +27 -0
  373. package/skills/lark-whiteboard/routes/svg-edit.md +85 -0
  374. package/skills/lark-whiteboard/routes/svg.md +54 -0
  375. package/skills/lark-whiteboard/scenes/architecture.md +433 -0
  376. package/skills/lark-whiteboard/scenes/bar-chart.md +187 -0
  377. package/skills/lark-whiteboard/scenes/comparison.md +135 -0
  378. package/skills/lark-whiteboard/scenes/fishbone.md +238 -0
  379. package/skills/lark-whiteboard/scenes/flowchart.md +185 -0
  380. package/skills/lark-whiteboard/scenes/flywheel.md +195 -0
  381. package/skills/lark-whiteboard/scenes/funnel.md +101 -0
  382. package/skills/lark-whiteboard/scenes/line-chart.md +214 -0
  383. package/skills/lark-whiteboard/scenes/mermaid.md +130 -0
  384. package/skills/lark-whiteboard/scenes/milestone.md +139 -0
  385. package/skills/lark-whiteboard/scenes/organization.md +173 -0
  386. package/skills/lark-whiteboard/scenes/photo-showcase.md +126 -0
  387. package/skills/lark-whiteboard/scenes/pyramid.md +99 -0
  388. package/skills/lark-whiteboard/scenes/swimlane.md +371 -0
  389. package/skills/lark-whiteboard/scenes/treemap.md +216 -0
  390. package/skills/lark-wiki/SKILL.md +110 -0
  391. package/skills/lark-wiki/references/lark-wiki-delete-space.md +205 -0
  392. package/skills/lark-wiki/references/lark-wiki-member-add.md +67 -0
  393. package/skills/lark-wiki/references/lark-wiki-member-list.md +76 -0
  394. package/skills/lark-wiki/references/lark-wiki-member-remove.md +61 -0
  395. package/skills/lark-wiki/references/lark-wiki-move.md +183 -0
  396. package/skills/lark-wiki/references/lark-wiki-node-copy.md +72 -0
  397. package/skills/lark-wiki/references/lark-wiki-node-create.md +127 -0
  398. package/skills/lark-wiki/references/lark-wiki-node-delete.md +62 -0
  399. package/skills/lark-wiki/references/lark-wiki-node-get.md +57 -0
  400. package/skills/lark-wiki/references/lark-wiki-node-list.md +88 -0
  401. package/skills/lark-wiki/references/lark-wiki-space-create.md +46 -0
  402. package/skills/lark-wiki/references/lark-wiki-space-list.md +68 -0
  403. package/skills/lark-workflow-meeting-summary/SKILL.md +122 -0
  404. package/skills/lark-workflow-standup-report/SKILL.md +122 -0
@@ -0,0 +1,367 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright (c) 2026 Lark Technologies Pte. Ltd.
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import re
9
+ import sys
10
+ import xml.etree.ElementTree as ET
11
+ from difflib import SequenceMatcher
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+
16
+ class XmlTextOverlapLintError(Exception):
17
+ pass
18
+
19
+
20
+ def fail(message: str) -> None:
21
+ raise XmlTextOverlapLintError(message)
22
+
23
+
24
+ def read_file(file_path: str | Path) -> str:
25
+ return Path(file_path).read_text(encoding="utf-8")
26
+
27
+
28
+ def parse_args(argv: list[str]) -> dict[str, Any]:
29
+ options: dict[str, Any] = {}
30
+ index = 0
31
+ while index < len(argv):
32
+ token = argv[index]
33
+ if not token.startswith("--"):
34
+ fail(f"unexpected argument: {token}")
35
+ key = token[2:]
36
+ next_token = argv[index + 1] if index + 1 < len(argv) else None
37
+ if next_token is None or next_token.startswith("--"):
38
+ options[key] = True
39
+ index += 1
40
+ continue
41
+ options[key] = next_token
42
+ index += 2
43
+ return options
44
+
45
+
46
+ def extract_attribute(tag_source: str, name: str) -> str | None:
47
+ match = re.search(fr'{re.escape(name)}="([^"]+)"', tag_source)
48
+ return match.group(1) if match else None
49
+
50
+
51
+ def extract_numeric_attribute(tag_source: str, name: str) -> int | float | None:
52
+ raw = extract_attribute(tag_source, name)
53
+ if raw is None:
54
+ return None
55
+ try:
56
+ value = float(raw)
57
+ except ValueError:
58
+ return None
59
+ return int(value) if value.is_integer() else value
60
+
61
+
62
+ def strip_xml(value: str) -> str:
63
+ stripped = re.sub(r"<!\[CDATA\[([\s\S]*?)\]\]>", r"\1", value)
64
+ stripped = re.sub(r"<[^>]+>", " ", stripped)
65
+ stripped = stripped.replace("&nbsp;", " ")
66
+ stripped = stripped.replace("&amp;", "&")
67
+ stripped = stripped.replace("&lt;", "<")
68
+ stripped = stripped.replace("&gt;", ">")
69
+ stripped = stripped.replace("&quot;", '"')
70
+ stripped = stripped.replace("&#39;", "'")
71
+ return re.sub(r"\s+", " ", stripped).strip()
72
+
73
+
74
+ def xml_local_name(tag: str) -> str:
75
+ return tag.rsplit("}", 1)[-1] if tag.startswith("{") else tag
76
+
77
+
78
+ def extract_error_context(xml: str, line: int | None, column: int | None, radius: int = 40) -> str | None:
79
+ if line is None or column is None:
80
+ return None
81
+ lines = xml.splitlines()
82
+ if line < 1 or line > len(lines):
83
+ return None
84
+ source_line = lines[line - 1]
85
+ start = max(column - radius, 0)
86
+ end = min(column + radius, len(source_line))
87
+ return source_line[start:end].strip()
88
+
89
+
90
+ def build_xml_error_issue(error: ET.ParseError, xml: str) -> dict[str, Any]:
91
+ line, column = getattr(error, "position", (None, None))
92
+ return {
93
+ "level": "error",
94
+ "code": "xml_not_well_formed",
95
+ "message": f"XML is not well-formed: {error}",
96
+ "line": line,
97
+ "column": column,
98
+ "context": extract_error_context(xml, line, column),
99
+ "hint": (
100
+ "Escape raw user text before placing it in XML. In text nodes and attribute values, bare & must be "
101
+ "written as &amp;. In text nodes, write < as &lt; and > as &gt;. For attribute URLs, use a=1&amp;b=2."
102
+ ),
103
+ }
104
+
105
+
106
+ def validate_xml_well_formed(xml: str) -> dict[str, Any] | None:
107
+ try:
108
+ root = ET.fromstring(xml)
109
+ except ET.ParseError as error:
110
+ return build_xml_error_issue(error, xml)
111
+
112
+ root_name = xml_local_name(root.tag)
113
+ if root_name not in {"presentation", "slide"}:
114
+ fail("input must contain a <presentation> or <slide> root")
115
+ return None
116
+
117
+
118
+ def parse_presentation(xml: str) -> dict[str, Any]:
119
+ presentation_match = re.search(r"<presentation\b([^>]*)>", xml)
120
+ if presentation_match:
121
+ return {
122
+ "width": int(float(extract_attribute(presentation_match.group(1), "width") or 960)),
123
+ "height": int(float(extract_attribute(presentation_match.group(1), "height") or 540)),
124
+ "slides": re.findall(r"<slide\b[\s\S]*?</slide>", xml),
125
+ }
126
+ slide_match = re.findall(r"<slide\b[\s\S]*?</slide>", xml)
127
+ if slide_match:
128
+ return {"width": 960, "height": 540, "slides": slide_match}
129
+ fail("input must contain a <presentation> or <slide> root")
130
+
131
+
132
+ def extract_elements(slide_xml: str) -> list[dict[str, Any]]:
133
+ elements: list[dict[str, Any]] = []
134
+ for match in re.finditer(r"<shape\b([^>]*)>([\s\S]*?)</shape>", slide_xml):
135
+ attrs, content = match.group(1), match.group(2)
136
+ x = extract_numeric_attribute(attrs, "topLeftX")
137
+ y = extract_numeric_attribute(attrs, "topLeftY")
138
+ width = extract_numeric_attribute(attrs, "width")
139
+ height = extract_numeric_attribute(attrs, "height")
140
+ if all(value is not None for value in [x, y, width, height]):
141
+ font_size = float(extract_attribute(content, "fontSize") or extract_attribute(attrs, "fontSize") or 16)
142
+ elements.append(
143
+ {
144
+ "id": f"shape-{len(elements) + 1}",
145
+ "kind": "shape",
146
+ "type": extract_attribute(attrs, "type") or "shape",
147
+ "textType": extract_attribute(content, "textType"),
148
+ "x": x,
149
+ "y": y,
150
+ "width": width,
151
+ "height": height,
152
+ "fontSize": font_size,
153
+ "text": strip_xml(content),
154
+ }
155
+ )
156
+
157
+ for match in re.finditer(r"<(img|table|chart)\b([^>]*)/?>", slide_xml):
158
+ attrs = match.group(2)
159
+ x = extract_numeric_attribute(attrs, "topLeftX")
160
+ y = extract_numeric_attribute(attrs, "topLeftY")
161
+ width = extract_numeric_attribute(attrs, "width")
162
+ height = extract_numeric_attribute(attrs, "height")
163
+ if all(value is not None for value in [x, y, width, height]):
164
+ elements.append(
165
+ {
166
+ "id": f"{match.group(1)}-{len(elements) + 1}",
167
+ "kind": match.group(1),
168
+ "type": match.group(1),
169
+ "x": x,
170
+ "y": y,
171
+ "width": width,
172
+ "height": height,
173
+ }
174
+ )
175
+ return elements
176
+
177
+
178
+ def intersects(left: dict[str, Any], right: dict[str, Any]) -> bool:
179
+ return (
180
+ left["x"] < right["x"] + right["width"]
181
+ and left["x"] + left["width"] > right["x"]
182
+ and left["y"] < right["y"] + right["height"]
183
+ and left["y"] + left["height"] > right["y"]
184
+ )
185
+
186
+
187
+ def is_text_element(element: dict[str, Any]) -> bool:
188
+ return element["kind"] == "shape" and element["type"] == "text"
189
+
190
+
191
+ def has_text_content(element: dict[str, Any]) -> bool:
192
+ return bool(element.get("text"))
193
+
194
+
195
+ def is_decorative_text(element: dict[str, Any]) -> bool:
196
+ text = element.get("text") or ""
197
+ return bool(text) and re.search(r"[A-Za-z0-9\u4e00-\u9fff]", text) is None
198
+
199
+
200
+ def normalize_text_for_overlap(text: str) -> str:
201
+ return re.sub(r"\s+", "", text)
202
+
203
+
204
+ def is_similar_text_overlay(left: dict[str, Any], right: dict[str, Any]) -> bool:
205
+ left_text = normalize_text_for_overlap(left.get("text") or "")
206
+ right_text = normalize_text_for_overlap(right.get("text") or "")
207
+ if not left_text or not right_text:
208
+ return False
209
+ if left_text == right_text or left_text in right_text or right_text in left_text:
210
+ return True
211
+ return SequenceMatcher(None, left_text, right_text).ratio() >= 0.75
212
+
213
+
214
+ def estimate_text_line_count(element: dict[str, Any]) -> int:
215
+ font_size = element["fontSize"] if isinstance(element["fontSize"], (int, float)) else 16
216
+ chars_per_line = max(1, int(element["width"] // max(font_size * 0.55, 1)))
217
+ paragraphs = [paragraph for paragraph in re.split(r"\n+", element["text"]) if paragraph]
218
+ line_count = 0
219
+ for paragraph in paragraphs:
220
+ logical_length = max(len(paragraph), 1)
221
+ line_count += max(1, -(-logical_length // chars_per_line))
222
+ return max(line_count, 1)
223
+
224
+
225
+ def estimate_text_visual_bbox(element: dict[str, Any]) -> dict[str, int | float] | None:
226
+ if not is_text_element(element) or not has_text_content(element) or is_decorative_text(element):
227
+ return None
228
+
229
+ font_size = element["fontSize"] if isinstance(element["fontSize"], (int, float)) else 16
230
+ char_width = max(font_size * 0.55, 1)
231
+ line_count = estimate_text_line_count(element)
232
+ visual_width = min(element["width"], max(1, len(element["text"]) * char_width))
233
+ visual_height = min(element["height"], max(1, line_count * font_size * 1.2))
234
+ return {
235
+ "x": element["x"],
236
+ "y": element["y"],
237
+ "width": visual_width,
238
+ "height": visual_height,
239
+ }
240
+
241
+
242
+ def intersection_area(left: dict[str, Any], right: dict[str, Any]) -> int | float:
243
+ width = min(left["x"] + left["width"], right["x"] + right["width"]) - max(left["x"], right["x"])
244
+ height = min(left["y"] + left["height"], right["y"] + right["height"]) - max(left["y"], right["y"])
245
+ if width <= 0 or height <= 0:
246
+ return 0
247
+ return width * height
248
+
249
+
250
+ def is_template_text_stack(left: dict[str, Any], right: dict[str, Any]) -> bool:
251
+ if not (is_text_element(left) and is_text_element(right)):
252
+ return False
253
+ if not (has_text_content(left) and has_text_content(right)):
254
+ return True
255
+ top, bottom = sorted([left, right], key=lambda element: element["y"])
256
+ top_type = top.get("textType")
257
+ bottom_type = bottom.get("textType")
258
+ allowed_pairs = {
259
+ ("title", "sub-headline"),
260
+ ("title", None),
261
+ ("headline", "headline"),
262
+ ("headline", None),
263
+ }
264
+ if (top_type, bottom_type) not in allowed_pairs:
265
+ return False
266
+ same_column = abs(top["x"] - bottom["x"]) <= 4
267
+ vertical_offset = bottom["y"] - top["y"]
268
+ top_font_size = float(top.get("fontSize", 16))
269
+ return same_column and vertical_offset >= top_font_size * 0.75
270
+
271
+
272
+ def should_flag_overlap(left: dict[str, Any], right: dict[str, Any]) -> bool:
273
+ if is_text_element(left) and not has_text_content(left):
274
+ return False
275
+ if is_text_element(right) and not has_text_content(right):
276
+ return False
277
+ if is_template_text_stack(left, right):
278
+ return False
279
+ if is_text_element(left) and is_text_element(right):
280
+ if is_similar_text_overlay(left, right):
281
+ return False
282
+ left_visual = estimate_text_visual_bbox(left)
283
+ right_visual = estimate_text_visual_bbox(right)
284
+ if left_visual is None or right_visual is None:
285
+ return False
286
+ overlap_area = intersection_area(left_visual, right_visual)
287
+ if overlap_area <= 0:
288
+ return False
289
+ smaller_area = min(
290
+ left_visual["width"] * left_visual["height"],
291
+ right_visual["width"] * right_visual["height"],
292
+ )
293
+ return smaller_area > 0 and overlap_area / smaller_area >= 0.30
294
+ return False
295
+
296
+
297
+ def lint_slide(slide_xml: str, slide_number: int) -> dict[str, Any]:
298
+ elements = extract_elements(slide_xml)
299
+ issues: list[dict[str, Any]] = []
300
+
301
+ for index, left in enumerate(elements):
302
+ for right in elements[index + 1 :]:
303
+ if not intersects(left, right) or not should_flag_overlap(left, right):
304
+ continue
305
+ issues.append(
306
+ {
307
+ "level": "error",
308
+ "code": "bbox_overlap",
309
+ "elements": [left["id"], right["id"]],
310
+ "message": f'{left["id"]} overlaps {right["id"]}',
311
+ }
312
+ )
313
+
314
+ return {"slide_number": slide_number, "element_count": len(elements), "issues": issues}
315
+
316
+
317
+ def lint_xml(xml: str, source_path: str | None = None) -> dict[str, Any]:
318
+ xml_error = validate_xml_well_formed(xml)
319
+ if xml_error:
320
+ return {
321
+ "file": source_path,
322
+ "slide_size": {"width": 960, "height": 540},
323
+ "summary": {"slide_count": 0, "error_count": 1, "warning_count": 0},
324
+ "issues": [xml_error],
325
+ "slides": [],
326
+ }
327
+
328
+ presentation = parse_presentation(xml)
329
+ slides = [
330
+ lint_slide(slide_xml, index + 1)
331
+ for index, slide_xml in enumerate(presentation["slides"])
332
+ ]
333
+ error_count = sum(1 for slide in slides for issue in slide["issues"] if issue["level"] == "error")
334
+ warning_count = sum(1 for slide in slides for issue in slide["issues"] if issue["level"] == "warning")
335
+ return {
336
+ "file": source_path,
337
+ "slide_size": {"width": presentation["width"], "height": presentation["height"]},
338
+ "summary": {"slide_count": len(slides), "error_count": error_count, "warning_count": warning_count},
339
+ "slides": slides,
340
+ }
341
+
342
+
343
+ def print_usage() -> None:
344
+ print("Usage:\n python3 xml_text_overlap_lint.py --input <presentation.xml>", file=sys.stderr)
345
+
346
+
347
+ def run_cli(argv: list[str] | None = None) -> None:
348
+ options = parse_args(argv or sys.argv[1:])
349
+ if options.get("help") or options.get("--help"):
350
+ print_usage()
351
+ raise SystemExit(0)
352
+ if not options.get("input"):
353
+ print_usage()
354
+ fail("--input is required")
355
+ input_path = Path(options["input"]).resolve()
356
+ result = lint_xml(read_file(input_path), str(input_path))
357
+ print(json.dumps(result, ensure_ascii=False, indent=2))
358
+ if result["summary"]["error_count"] > 0:
359
+ raise SystemExit(1)
360
+
361
+
362
+ if __name__ == "__main__":
363
+ try:
364
+ run_cli()
365
+ except XmlTextOverlapLintError as error:
366
+ print(f"xml-text-overlap-lint error: {error}", file=sys.stderr)
367
+ raise SystemExit(1) from error
@@ -0,0 +1,299 @@
1
+ # Copyright (c) 2026 Lark Technologies Pte. Ltd.
2
+ # SPDX-License-Identifier: MIT
3
+ from __future__ import annotations
4
+
5
+ import unittest
6
+
7
+ import xml_text_overlap_lint
8
+
9
+
10
+ class XmlTextOverlapLintTest(unittest.TestCase):
11
+ def assertNoXmlTextOverlapLintIssues(self, result: dict, sample_name: str) -> None:
12
+ issue_summaries = []
13
+ for slide in result.get("slides", []):
14
+ for issue in slide.get("issues", []):
15
+ issue_summaries.append(
16
+ f"slide {slide['slide_number']}: {issue['level']} {issue['code']} {issue['message']}"
17
+ )
18
+ if result.get("issues"):
19
+ for issue in result["issues"]:
20
+ issue_summaries.append(f"{issue['level']} {issue['code']} {issue['message']}")
21
+ self.assertEqual(
22
+ result["summary"]["error_count"],
23
+ 0,
24
+ f"{sample_name} has XML text overlap lint errors:\n" + "\n".join(issue_summaries),
25
+ )
26
+ self.assertEqual(
27
+ result["summary"]["warning_count"],
28
+ 0,
29
+ f"{sample_name} has XML text overlap lint warnings:\n" + "\n".join(issue_summaries),
30
+ )
31
+
32
+ def test_xml_text_overlap_lint_accepts_inline_fixture_xml_samples(self) -> None:
33
+ samples = {
34
+ "image-led-cover": """
35
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
36
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
37
+ <style><fill><fillColor color="rgb(15,23,42)"/></fill></style>
38
+ <data>
39
+ <img src="tok" topLeftX="560" topLeftY="0" width="400" height="540"/>
40
+ <shape type="text" topLeftX="64" topLeftY="150" width="420" height="70">
41
+ <content textType="title"><p><span fontSize="42">Quarterly Review</span></p></content>
42
+ </shape>
43
+ <shape type="text" topLeftX="64" topLeftY="235" width="420" height="36">
44
+ <content textType="sub-headline"><p><span fontSize="20">Focus, progress, and next steps</span></p></content>
45
+ </shape>
46
+ </data>
47
+ </slide>
48
+ </presentation>
49
+ """,
50
+ "content-grid": """
51
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
52
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
53
+ <data>
54
+ <shape type="text" topLeftX="60" topLeftY="44" width="620" height="46">
55
+ <content textType="title"><p><span fontSize="30">Execution Snapshot</span></p></content>
56
+ </shape>
57
+ <shape type="rect" topLeftX="60" topLeftY="126" width="250" height="150"/>
58
+ <shape type="text" topLeftX="84" topLeftY="152" width="200" height="36">
59
+ <content textType="headline"><p><span fontSize="22">Plan</span></p></content>
60
+ </shape>
61
+ <shape type="rect" topLeftX="355" topLeftY="126" width="250" height="150"/>
62
+ <shape type="text" topLeftX="379" topLeftY="152" width="200" height="36">
63
+ <content textType="headline"><p><span fontSize="22">Build</span></p></content>
64
+ </shape>
65
+ <shape type="rect" topLeftX="650" topLeftY="126" width="250" height="150"/>
66
+ <shape type="text" topLeftX="674" topLeftY="152" width="200" height="36">
67
+ <content textType="headline"><p><span fontSize="22">Launch</span></p></content>
68
+ </shape>
69
+ </data>
70
+ </slide>
71
+ </presentation>
72
+ """,
73
+ }
74
+ self.assertTrue(samples)
75
+ for sample_name, sample_xml in samples.items():
76
+ with self.subTest(sample=sample_name):
77
+ result = xml_text_overlap_lint.lint_xml(
78
+ sample_xml,
79
+ sample_name,
80
+ )
81
+ self.assertNoXmlTextOverlapLintIssues(result, sample_name)
82
+
83
+ def test_lint_xml_reports_unescaped_ampersand_in_text(self) -> None:
84
+ result = xml_text_overlap_lint.lint_xml(
85
+ """
86
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
87
+ <data>
88
+ <shape type="text" topLeftX="80" topLeftY="80" width="300" height="60">
89
+ <content textType="body"><p>Q&A</p></content>
90
+ </shape>
91
+ </data>
92
+ </slide>
93
+ """
94
+ )
95
+ issue = result["issues"][0]
96
+ self.assertEqual(result["summary"]["error_count"], 1)
97
+ self.assertEqual(issue["code"], "xml_not_well_formed")
98
+ self.assertIsInstance(issue["line"], int)
99
+ self.assertIsInstance(issue["column"], int)
100
+ self.assertIn("Q&A", issue["context"])
101
+ self.assertIn("&amp;", issue["hint"])
102
+
103
+ def test_lint_xml_reports_unescaped_ampersand_in_attribute(self) -> None:
104
+ result = xml_text_overlap_lint.lint_xml(
105
+ """
106
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
107
+ <data>
108
+ <shape type="text" topLeftX="80" topLeftY="80" width="300" height="60">
109
+ <content textType="body"><p><a href="https://example.com/?a=1&b=2">link</a></p></content>
110
+ </shape>
111
+ </data>
112
+ </slide>
113
+ """
114
+ )
115
+ issue = result["issues"][0]
116
+ self.assertEqual(issue["code"], "xml_not_well_formed")
117
+ self.assertIn("attribute", issue["hint"])
118
+ self.assertIn("a=1&amp;b=2", issue["hint"])
119
+
120
+ def test_lint_xml_accepts_escaped_entities_without_suspicious_entity_warning(self) -> None:
121
+ result = xml_text_overlap_lint.lint_xml(
122
+ """
123
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
124
+ <data>
125
+ <shape type="text" topLeftX="80" topLeftY="80" width="300" height="60">
126
+ <content textType="body"><p>Q&amp;A</p></content>
127
+ </shape>
128
+ </data>
129
+ </slide>
130
+ """
131
+ )
132
+ self.assertEqual(result["summary"]["error_count"], 0)
133
+ self.assertNotIn("issues", result)
134
+
135
+ def test_lint_xml_accepts_chinese_full_width_punctuation(self) -> None:
136
+ result = xml_text_overlap_lint.lint_xml(
137
+ """
138
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
139
+ <data>
140
+ <shape type="text" topLeftX="80" topLeftY="80" width="620" height="90">
141
+ <content textType="body"><p>承诺:按期交付;持续复盘|风险透明</p></content>
142
+ </shape>
143
+ </data>
144
+ </slide>
145
+ """
146
+ )
147
+ self.assertEqual(result["summary"]["error_count"], 0)
148
+
149
+ def test_lint_xml_single_slide_uses_default_canvas_without_bounds_checks(self) -> None:
150
+ result = xml_text_overlap_lint.lint_xml(
151
+ """
152
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
153
+ <data>
154
+ <shape type="text" topLeftX="1000" topLeftY="500" width="120" height="80">
155
+ <content textType="body"><p>Body text outside the canvas</p></content>
156
+ </shape>
157
+ </data>
158
+ </slide>
159
+ """
160
+ )
161
+ self.assertEqual(result["slide_size"], {"width": 960, "height": 540})
162
+ self.assertEqual(result["summary"]["slide_count"], 1)
163
+ self.assertEqual(result["summary"]["error_count"], 0)
164
+
165
+ def test_lint_xml_detects_overlapping_text_boxes(self) -> None:
166
+ result = xml_text_overlap_lint.lint_xml(
167
+ """
168
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
169
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
170
+ <data>
171
+ <shape type="text" topLeftX="80" topLeftY="80" width="300" height="60">
172
+ <content textType="title"><p>Title</p></content>
173
+ </shape>
174
+ <shape type="text" topLeftX="80" topLeftY="80" width="300" height="80">
175
+ <content textType="body"><p>Body</p></content>
176
+ </shape>
177
+ </data>
178
+ </slide>
179
+ </presentation>
180
+ """
181
+ )
182
+ self.assertEqual(result["summary"]["error_count"], 1)
183
+ self.assertEqual(result["slides"][0]["issues"][0]["code"], "bbox_overlap")
184
+
185
+ def test_lint_xml_does_not_check_bounds_or_text_height(self) -> None:
186
+ result = xml_text_overlap_lint.lint_xml(
187
+ """
188
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
189
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
190
+ <data>
191
+ <shape type="text" topLeftX="80" topLeftY="80" width="180" height="20">
192
+ <content textType="body" fontSize="18"><p>This paragraph is intentionally much longer than the box can safely contain.</p></content>
193
+ </shape>
194
+ <shape type="text" topLeftX="1000" topLeftY="500" width="120" height="80">
195
+ <content textType="body"><p>Body text outside the canvas</p></content>
196
+ </shape>
197
+ </data>
198
+ </slide>
199
+ </presentation>
200
+ """
201
+ )
202
+ self.assertEqual(result["summary"]["error_count"], 0)
203
+ self.assertEqual(result["summary"]["warning_count"], 0)
204
+
205
+ def test_lint_xml_allows_template_style_bleed_and_text_over_images(self) -> None:
206
+ result = xml_text_overlap_lint.lint_xml(
207
+ """
208
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
209
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
210
+ <data>
211
+ <img src="tok" topLeftX="-120" topLeftY="20" width="360" height="360"/>
212
+ <shape type="text" topLeftX="40" topLeftY="80" width="180" height="80">
213
+ <content textType="title" fontSize="44"><p>Title</p></content>
214
+ </shape>
215
+ <shape type="text" topLeftX="40" topLeftY="120" width="180" height="40">
216
+ <content textType="sub-headline" fontSize="20"><p>Subtitle</p></content>
217
+ </shape>
218
+ </data>
219
+ </slide>
220
+ </presentation>
221
+ """
222
+ )
223
+ self.assertEqual(result["summary"]["error_count"], 0)
224
+ self.assertEqual(result["summary"]["warning_count"], 0)
225
+
226
+ def test_lint_xml_does_not_check_small_out_of_bounds_elements(self) -> None:
227
+ result = xml_text_overlap_lint.lint_xml(
228
+ """
229
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
230
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
231
+ <data>
232
+ <img src="tok" topLeftX="-20" topLeftY="20" width="120" height="120"/>
233
+ </data>
234
+ </slide>
235
+ </presentation>
236
+ """
237
+ )
238
+ self.assertEqual(result["summary"]["error_count"], 0)
239
+
240
+ def test_lint_xml_ignores_obviously_misplaced_large_visuals(self) -> None:
241
+ result = xml_text_overlap_lint.lint_xml(
242
+ """
243
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
244
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
245
+ <data>
246
+ <img src="right" topLeftX="780" topLeftY="0" width="500" height="540"/>
247
+ <img src="bottom" topLeftX="0" topLeftY="430" width="900" height="280"/>
248
+ </data>
249
+ </slide>
250
+ </presentation>
251
+ """
252
+ )
253
+ self.assertEqual(result["summary"]["error_count"], 0)
254
+
255
+ def test_lint_xml_allows_reasonable_large_visual_bleed(self) -> None:
256
+ result = xml_text_overlap_lint.lint_xml(
257
+ """
258
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
259
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
260
+ <data>
261
+ <img src="tok" topLeftX="-80" topLeftY="-20" width="1080" height="600"/>
262
+ </data>
263
+ </slide>
264
+ </presentation>
265
+ """
266
+ )
267
+ self.assertEqual(result["summary"]["error_count"], 0)
268
+
269
+ def test_lint_xml_detects_invalid_template_text_stack_overlap(self) -> None:
270
+ cases = [
271
+ (
272
+ "subtitle-too-high",
273
+ """
274
+ <shape type="text" topLeftX="40" topLeftY="80" width="240" height="90">
275
+ <content textType="title" fontSize="44"><p>Title</p></content>
276
+ </shape>
277
+ <shape type="text" topLeftX="40" topLeftY="90" width="240" height="80">
278
+ <content textType="sub-headline" fontSize="20"><p>Subtitle</p></content>
279
+ </shape>
280
+ """,
281
+ ),
282
+ ]
283
+ for name, shapes in cases:
284
+ with self.subTest(name=name):
285
+ result = xml_text_overlap_lint.lint_xml(
286
+ f"""
287
+ <presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
288
+ <slide xmlns="http://www.larkoffice.com/sml/2.0">
289
+ <data>{shapes}</data>
290
+ </slide>
291
+ </presentation>
292
+ """
293
+ )
294
+ self.assertEqual(result["summary"]["error_count"], 1)
295
+ self.assertEqual(result["slides"][0]["issues"][0]["code"], "bbox_overlap")
296
+
297
+
298
+ if __name__ == "__main__":
299
+ unittest.main()