@yandy0725/pi-lark 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/README.zh.md +30 -0
- package/package.json +36 -0
- package/skills/lark-approval/SKILL.md +56 -0
- package/skills/lark-approval/references/lark-approval-initiate.md +196 -0
- package/skills/lark-approval/references/lark-approval-instance-form-control-parameters.md +606 -0
- package/skills/lark-approval/references/lark-approval-instance-value-sourcing.md +108 -0
- package/skills/lark-apps/SKILL.md +78 -0
- package/skills/lark-apps/references/lark-apps-access-scope-get.md +28 -0
- package/skills/lark-apps/references/lark-apps-access-scope-set.md +40 -0
- package/skills/lark-apps/references/lark-apps-cloud-dev.md +120 -0
- package/skills/lark-apps/references/lark-apps-create.md +40 -0
- package/skills/lark-apps/references/lark-apps-db-env-create.md +31 -0
- package/skills/lark-apps/references/lark-apps-db-execute.md +40 -0
- package/skills/lark-apps/references/lark-apps-db-table-get.md +29 -0
- package/skills/lark-apps/references/lark-apps-db-table-list.md +31 -0
- package/skills/lark-apps/references/lark-apps-env-pull.md +35 -0
- package/skills/lark-apps/references/lark-apps-git-credential.md +37 -0
- package/skills/lark-apps/references/lark-apps-html-publish.md +57 -0
- package/skills/lark-apps/references/lark-apps-init.md +37 -0
- package/skills/lark-apps/references/lark-apps-list.md +37 -0
- package/skills/lark-apps/references/lark-apps-local-dev.md +76 -0
- package/skills/lark-apps/references/lark-apps-release-create.md +30 -0
- package/skills/lark-apps/references/lark-apps-release-get.md +28 -0
- package/skills/lark-apps/references/lark-apps-release-list.md +31 -0
- package/skills/lark-apps/references/lark-apps-session-messages-list.md +53 -0
- package/skills/lark-apps/references/lark-apps-update.md +30 -0
- package/skills/lark-attendance/SKILL.md +57 -0
- package/skills/lark-base/SKILL.md +157 -0
- package/skills/lark-base/references/dashboard-block-data-config.md +350 -0
- package/skills/lark-base/references/formula-field-guide.md +737 -0
- package/skills/lark-base/references/lark-base-cell-value.md +153 -0
- package/skills/lark-base/references/lark-base-dashboard-block-get-data.md +717 -0
- package/skills/lark-base/references/lark-base-dashboard.md +238 -0
- package/skills/lark-base/references/lark-base-data-analysis-sop.md +210 -0
- package/skills/lark-base/references/lark-base-data-query-guide.md +61 -0
- package/skills/lark-base/references/lark-base-data-query.md +452 -0
- package/skills/lark-base/references/lark-base-field-create.md +103 -0
- package/skills/lark-base/references/lark-base-field-json.md +489 -0
- package/skills/lark-base/references/lark-base-field-update.md +171 -0
- package/skills/lark-base/references/lark-base-form-detail.md +71 -0
- package/skills/lark-base/references/lark-base-form-questions-create.md +118 -0
- package/skills/lark-base/references/lark-base-form-questions-update.md +92 -0
- package/skills/lark-base/references/lark-base-form-submit.md +170 -0
- package/skills/lark-base/references/lark-base-record-batch-create.md +57 -0
- package/skills/lark-base/references/lark-base-record-batch-update.md +52 -0
- package/skills/lark-base/references/lark-base-record-history-list.md +43 -0
- package/skills/lark-base/references/lark-base-record-upsert.md +63 -0
- package/skills/lark-base/references/lark-base-role-guide.md +65 -0
- package/skills/lark-base/references/lark-base-view-set-filter.md +189 -0
- package/skills/lark-base/references/lark-base-workflow-guide.md +830 -0
- package/skills/lark-base/references/lark-base-workflow-schema.md +1071 -0
- package/skills/lark-base/references/lookup-field-guide.md +512 -0
- package/skills/lark-base/references/role-config.md +549 -0
- package/skills/lark-calendar/SKILL.md +137 -0
- package/skills/lark-calendar/references/lark-calendar-agenda.md +78 -0
- package/skills/lark-calendar/references/lark-calendar-create.md +106 -0
- package/skills/lark-calendar/references/lark-calendar-freebusy.md +124 -0
- package/skills/lark-calendar/references/lark-calendar-meeting.md +40 -0
- package/skills/lark-calendar/references/lark-calendar-room-find.md +113 -0
- package/skills/lark-calendar/references/lark-calendar-rsvp.md +42 -0
- package/skills/lark-calendar/references/lark-calendar-schedule-meeting.md +265 -0
- package/skills/lark-calendar/references/lark-calendar-search-event.md +29 -0
- package/skills/lark-calendar/references/lark-calendar-suggestion.md +125 -0
- package/skills/lark-calendar/references/lark-calendar-update.md +105 -0
- package/skills/lark-contact/SKILL.md +59 -0
- package/skills/lark-contact/references/lark-contact-get-user.md +19 -0
- package/skills/lark-contact/references/lark-contact-search-user.md +124 -0
- package/skills/lark-doc/SKILL.md +79 -0
- package/skills/lark-doc/references/lark-doc-create.md +79 -0
- package/skills/lark-doc/references/lark-doc-fetch.md +138 -0
- package/skills/lark-doc/references/lark-doc-md.md +76 -0
- package/skills/lark-doc/references/lark-doc-media-download.md +50 -0
- package/skills/lark-doc/references/lark-doc-media-insert.md +114 -0
- package/skills/lark-doc/references/lark-doc-media-preview.md +41 -0
- package/skills/lark-doc/references/lark-doc-resource-cover.md +70 -0
- package/skills/lark-doc/references/lark-doc-update.md +259 -0
- package/skills/lark-doc/references/lark-doc-whiteboard.md +154 -0
- package/skills/lark-doc/references/lark-doc-xml.md +181 -0
- package/skills/lark-doc/references/style/lark-doc-create-workflow.md +59 -0
- package/skills/lark-doc/references/style/lark-doc-style.md +86 -0
- package/skills/lark-doc/references/style/lark-doc-update-workflow.md +55 -0
- package/skills/lark-drive/SKILL.md +215 -0
- package/skills/lark-drive/references/lark-drive-add-comment.md +193 -0
- package/skills/lark-drive/references/lark-drive-apply-permission.md +77 -0
- package/skills/lark-drive/references/lark-drive-comment-location.md +193 -0
- package/skills/lark-drive/references/lark-drive-comments-guide.md +72 -0
- package/skills/lark-drive/references/lark-drive-cover.md +79 -0
- package/skills/lark-drive/references/lark-drive-create-folder.md +73 -0
- package/skills/lark-drive/references/lark-drive-create-shortcut.md +103 -0
- package/skills/lark-drive/references/lark-drive-delete.md +79 -0
- package/skills/lark-drive/references/lark-drive-download.md +31 -0
- package/skills/lark-drive/references/lark-drive-export-download.md +50 -0
- package/skills/lark-drive/references/lark-drive-export.md +145 -0
- package/skills/lark-drive/references/lark-drive-files-list.md +158 -0
- package/skills/lark-drive/references/lark-drive-import.md +170 -0
- package/skills/lark-drive/references/lark-drive-inspect.md +50 -0
- package/skills/lark-drive/references/lark-drive-member-add.md +66 -0
- package/skills/lark-drive/references/lark-drive-move.md +120 -0
- package/skills/lark-drive/references/lark-drive-permission-guide.md +41 -0
- package/skills/lark-drive/references/lark-drive-preview.md +87 -0
- package/skills/lark-drive/references/lark-drive-pull.md +137 -0
- package/skills/lark-drive/references/lark-drive-push.md +162 -0
- package/skills/lark-drive/references/lark-drive-reactions.md +113 -0
- package/skills/lark-drive/references/lark-drive-search.md +269 -0
- package/skills/lark-drive/references/lark-drive-secure-label.md +52 -0
- package/skills/lark-drive/references/lark-drive-status.md +137 -0
- package/skills/lark-drive/references/lark-drive-task-result.md +302 -0
- package/skills/lark-drive/references/lark-drive-upload.md +101 -0
- package/skills/lark-drive/references/lark-drive-version-delete.md +38 -0
- package/skills/lark-drive/references/lark-drive-version-get.md +71 -0
- package/skills/lark-drive/references/lark-drive-version-history.md +73 -0
- package/skills/lark-drive/references/lark-drive-version-revert.md +35 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-analysis.md +249 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-discovery.md +253 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-execution.md +200 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-planning.md +336 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize-rollback.md +308 -0
- package/skills/lark-drive/references/lark-drive-workflow-knowledge-organize.md +226 -0
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance-commands.md +168 -0
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance-outputs.md +424 -0
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance.md +207 -0
- package/skills/lark-drive/references/lark-drive-workflow.md +130 -0
- package/skills/lark-event/SKILL.md +154 -0
- package/skills/lark-event/references/lark-event-im.md +87 -0
- package/skills/lark-event/references/lark-event-minutes.md +54 -0
- package/skills/lark-event/references/lark-event-task.md +78 -0
- package/skills/lark-event/references/lark-event-vc.md +94 -0
- package/skills/lark-event/references/lark-event-whiteboard.md +67 -0
- package/skills/lark-im/SKILL.md +247 -0
- package/skills/lark-im/references/lark-im-card-action-reply.md +175 -0
- package/skills/lark-im/references/lark-im-chat-create.md +162 -0
- package/skills/lark-im/references/lark-im-chat-identity.md +55 -0
- package/skills/lark-im/references/lark-im-chat-list.md +166 -0
- package/skills/lark-im/references/lark-im-chat-messages-list.md +157 -0
- package/skills/lark-im/references/lark-im-chat-search.md +142 -0
- package/skills/lark-im/references/lark-im-chat-update.md +84 -0
- package/skills/lark-im/references/lark-im-feed-group-list-item.md +68 -0
- package/skills/lark-im/references/lark-im-feed-group-list.md +65 -0
- package/skills/lark-im/references/lark-im-feed-group-query-item.md +44 -0
- package/skills/lark-im/references/lark-im-feed-groups.md +452 -0
- package/skills/lark-im/references/lark-im-feed-shortcut-create.md +97 -0
- package/skills/lark-im/references/lark-im-feed-shortcut-list.md +103 -0
- package/skills/lark-im/references/lark-im-feed-shortcut-remove.md +48 -0
- package/skills/lark-im/references/lark-im-flag-cancel.md +67 -0
- package/skills/lark-im/references/lark-im-flag-create.md +67 -0
- package/skills/lark-im/references/lark-im-flag-list.md +100 -0
- package/skills/lark-im/references/lark-im-message-enrichment.md +54 -0
- package/skills/lark-im/references/lark-im-messages-mget.md +99 -0
- package/skills/lark-im/references/lark-im-messages-reply.md +267 -0
- package/skills/lark-im/references/lark-im-messages-resources-download.md +94 -0
- package/skills/lark-im/references/lark-im-messages-search.md +234 -0
- package/skills/lark-im/references/lark-im-messages-send.md +267 -0
- package/skills/lark-im/references/lark-im-reactions.md +299 -0
- package/skills/lark-im/references/lark-im-threads-messages-list.md +115 -0
- package/skills/lark-mail/SKILL.md +287 -0
- package/skills/lark-mail/assets/templates/job-application--resume.html +33 -0
- package/skills/lark-mail/assets/templates/newsletter--weekly-brief.html +50 -0
- package/skills/lark-mail/assets/templates/research--market-report.html +256 -0
- package/skills/lark-mail/assets/templates/weekly--personal-report.html +43 -0
- package/skills/lark-mail/assets/templates/weekly--team-report.html +9 -0
- package/skills/lark-mail/references/lark-mail-calendar-invite.md +36 -0
- package/skills/lark-mail/references/lark-mail-decline-receipt.md +115 -0
- package/skills/lark-mail/references/lark-mail-draft-create.md +127 -0
- package/skills/lark-mail/references/lark-mail-draft-edit.md +404 -0
- package/skills/lark-mail/references/lark-mail-forward.md +239 -0
- package/skills/lark-mail/references/lark-mail-html.md +333 -0
- package/skills/lark-mail/references/lark-mail-lint-html.md +243 -0
- package/skills/lark-mail/references/lark-mail-message.md +233 -0
- package/skills/lark-mail/references/lark-mail-messages.md +108 -0
- package/skills/lark-mail/references/lark-mail-recall.md +66 -0
- package/skills/lark-mail/references/lark-mail-recipient-search.md +59 -0
- package/skills/lark-mail/references/lark-mail-reply-all.md +213 -0
- package/skills/lark-mail/references/lark-mail-reply.md +249 -0
- package/skills/lark-mail/references/lark-mail-rules.md +31 -0
- package/skills/lark-mail/references/lark-mail-send-as.md +44 -0
- package/skills/lark-mail/references/lark-mail-send-receipt.md +120 -0
- package/skills/lark-mail/references/lark-mail-send-status.md +46 -0
- package/skills/lark-mail/references/lark-mail-send.md +222 -0
- package/skills/lark-mail/references/lark-mail-share-to-chat.md +87 -0
- package/skills/lark-mail/references/lark-mail-signature.md +98 -0
- package/skills/lark-mail/references/lark-mail-template-create.md +129 -0
- package/skills/lark-mail/references/lark-mail-template-update.md +150 -0
- package/skills/lark-mail/references/lark-mail-template.md +54 -0
- package/skills/lark-mail/references/lark-mail-thread.md +111 -0
- package/skills/lark-mail/references/lark-mail-triage.md +131 -0
- package/skills/lark-mail/references/lark-mail-watch.md +94 -0
- package/skills/lark-markdown/SKILL.md +69 -0
- package/skills/lark-markdown/references/lark-markdown-create.md +94 -0
- package/skills/lark-markdown/references/lark-markdown-diff.md +156 -0
- package/skills/lark-markdown/references/lark-markdown-fetch.md +79 -0
- package/skills/lark-markdown/references/lark-markdown-overwrite.md +85 -0
- package/skills/lark-markdown/references/lark-markdown-patch.md +160 -0
- package/skills/lark-minutes/SKILL.md +192 -0
- package/skills/lark-minutes/references/lark-minutes-detail.md +62 -0
- package/skills/lark-minutes/references/lark-minutes-download.md +137 -0
- package/skills/lark-minutes/references/lark-minutes-search.md +204 -0
- package/skills/lark-minutes/references/lark-minutes-speaker-replace.md +107 -0
- package/skills/lark-minutes/references/lark-minutes-summary.md +122 -0
- package/skills/lark-minutes/references/lark-minutes-todo.md +138 -0
- package/skills/lark-minutes/references/lark-minutes-update.md +41 -0
- package/skills/lark-minutes/references/lark-minutes-upload.md +104 -0
- package/skills/lark-note/SKILL.md +94 -0
- package/skills/lark-note/references/lark-note-detail.md +26 -0
- package/skills/lark-note/references/lark-note-transcript.md +23 -0
- package/skills/lark-okr/SKILL.md +115 -0
- package/skills/lark-okr/references/lark-okr-batch-create.md +106 -0
- package/skills/lark-okr/references/lark-okr-contentblock.md +359 -0
- package/skills/lark-okr/references/lark-okr-cycle-detail.md +84 -0
- package/skills/lark-okr/references/lark-okr-cycle-list.md +90 -0
- package/skills/lark-okr/references/lark-okr-entities.md +329 -0
- package/skills/lark-okr/references/lark-okr-image-upload.md +116 -0
- package/skills/lark-okr/references/lark-okr-indicator-update.md +80 -0
- package/skills/lark-okr/references/lark-okr-progress-create.md +81 -0
- package/skills/lark-okr/references/lark-okr-progress-delete.md +47 -0
- package/skills/lark-okr/references/lark-okr-progress-get.md +62 -0
- package/skills/lark-okr/references/lark-okr-progress-list.md +80 -0
- package/skills/lark-okr/references/lark-okr-progress-update.md +81 -0
- package/skills/lark-okr/references/lark-okr-reorder.md +81 -0
- package/skills/lark-okr/references/lark-okr-weight.md +96 -0
- package/skills/lark-openapi-explorer/SKILL.md +153 -0
- package/skills/lark-shared/SKILL.md +168 -0
- package/skills/lark-shared/references/lark-wiki-token-routing.md +42 -0
- package/skills/lark-sheets/SKILL.md +165 -0
- package/skills/lark-sheets/references/lark-sheets-batch-update.md +191 -0
- package/skills/lark-sheets/references/lark-sheets-chart.md +330 -0
- package/skills/lark-sheets/references/lark-sheets-conditional-format.md +179 -0
- package/skills/lark-sheets/references/lark-sheets-core-operations.md +103 -0
- package/skills/lark-sheets/references/lark-sheets-filter-view.md +137 -0
- package/skills/lark-sheets/references/lark-sheets-filter.md +130 -0
- package/skills/lark-sheets/references/lark-sheets-float-image.md +159 -0
- package/skills/lark-sheets/references/lark-sheets-formula-translation.md +267 -0
- package/skills/lark-sheets/references/lark-sheets-pivot-table.md +166 -0
- package/skills/lark-sheets/references/lark-sheets-range-operations.md +267 -0
- package/skills/lark-sheets/references/lark-sheets-read-data.md +235 -0
- package/skills/lark-sheets/references/lark-sheets-search-replace.md +111 -0
- package/skills/lark-sheets/references/lark-sheets-sheet-structure.md +212 -0
- package/skills/lark-sheets/references/lark-sheets-sparkline.md +149 -0
- package/skills/lark-sheets/references/lark-sheets-visual-standards.md +205 -0
- package/skills/lark-sheets/references/lark-sheets-workbook.md +395 -0
- package/skills/lark-sheets/references/lark-sheets-write-cells.md +565 -0
- package/skills/lark-sheets/scripts/sheets_df.py +32 -0
- package/skills/lark-skill-maker/SKILL.md +85 -0
- package/skills/lark-slides/SKILL.md +293 -0
- package/skills/lark-slides/assets/templates/administration--all_hands_meeting.xml +1999 -0
- package/skills/lark-slides/assets/templates/administration--annual_gala.xml +1160 -0
- package/skills/lark-slides/assets/templates/administration--company_intro.xml +1376 -0
- package/skills/lark-slides/assets/templates/administration--corporate_culture.xml +1765 -0
- package/skills/lark-slides/assets/templates/hr--employee_training.xml +912 -0
- package/skills/lark-slides/assets/templates/hr--employee_training_workshop.xml +1504 -0
- package/skills/lark-slides/assets/templates/hr--onboarding.xml +933 -0
- package/skills/lark-slides/assets/templates/marketing--brand_communication.xml +1367 -0
- package/skills/lark-slides/assets/templates/marketing--brand_logo_design.xml +1347 -0
- package/skills/lark-slides/assets/templates/marketing--brand_operations_plan.xml +1309 -0
- package/skills/lark-slides/assets/templates/marketing--business_plan.xml +1646 -0
- package/skills/lark-slides/assets/templates/marketing--marketing_plan.xml +1469 -0
- package/skills/lark-slides/assets/templates/marketing--marketing_strategy.xml +1484 -0
- package/skills/lark-slides/assets/templates/marketing--product_whitepaper.xml +1455 -0
- package/skills/lark-slides/assets/templates/marketing--roadshow_business_plan.xml +1506 -0
- package/skills/lark-slides/assets/templates/misc--book_sharing.xml +1338 -0
- package/skills/lark-slides/assets/templates/misc--club_event_plan.xml +4885 -0
- package/skills/lark-slides/assets/templates/misc--student_career_plan.xml +1854 -0
- package/skills/lark-slides/assets/templates/office--dark_general.xml +3763 -0
- package/skills/lark-slides/assets/templates/office--dept_annual_report.xml +1192 -0
- package/skills/lark-slides/assets/templates/office--light_general.xml +3378 -0
- package/skills/lark-slides/assets/templates/office--project_kickoff.xml +3152 -0
- package/skills/lark-slides/assets/templates/office--quarterly_review.xml +1253 -0
- package/skills/lark-slides/assets/templates/office--work_report.xml +1099 -0
- package/skills/lark-slides/assets/templates/office--work_summary.xml +4420 -0
- package/skills/lark-slides/assets/templates/office--work_summary_report.xml +1523 -0
- package/skills/lark-slides/assets/templates/operations--brand_logo_design.xml +1347 -0
- package/skills/lark-slides/assets/templates/operations--brand_operations_plan.xml +1309 -0
- package/skills/lark-slides/assets/templates/operations--marketing_plan.xml +1469 -0
- package/skills/lark-slides/assets/templates/operations--product_promotion.xml +687 -0
- package/skills/lark-slides/assets/templates/personal--experience_sharing.xml +2242 -0
- package/skills/lark-slides/assets/templates/personal--personal_resume.xml +2047 -0
- package/skills/lark-slides/assets/templates/personal--promotion_defense.xml +1099 -0
- package/skills/lark-slides/assets/templates/personal--promotion_report.xml +1039 -0
- package/skills/lark-slides/assets/templates/personal--self_intro.xml +696 -0
- package/skills/lark-slides/assets/templates/personal--teaching_sharing.xml +3013 -0
- package/skills/lark-slides/assets/templates/product--business_case_analysis.xml +1341 -0
- package/skills/lark-slides/assets/templates/product--market_analysis.xml +898 -0
- package/skills/lark-slides/assets/templates/product--product_analysis.xml +1537 -0
- package/skills/lark-slides/assets/templates/product--product_intro.xml +2838 -0
- package/skills/lark-slides/assets/templates/product--product_promotion.xml +687 -0
- package/skills/lark-slides/assets/templates/product--product_promotion_2.xml +687 -0
- package/skills/lark-slides/references/asset-planning.md +124 -0
- package/skills/lark-slides/references/examples.md +261 -0
- package/skills/lark-slides/references/iconpark-index.json +41901 -0
- package/skills/lark-slides/references/iconpark.md +46 -0
- package/skills/lark-slides/references/lark-slides-create.md +137 -0
- package/skills/lark-slides/references/lark-slides-edit-workflows.md +144 -0
- package/skills/lark-slides/references/lark-slides-media-upload.md +128 -0
- package/skills/lark-slides/references/lark-slides-replace-pages.md +95 -0
- package/skills/lark-slides/references/lark-slides-replace-slide.md +240 -0
- package/skills/lark-slides/references/lark-slides-screenshot.md +94 -0
- package/skills/lark-slides/references/lark-slides-whiteboard.md +330 -0
- package/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md +220 -0
- package/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md +123 -0
- package/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md +110 -0
- package/skills/lark-slides/references/lark-slides-xml-presentation-slide-replace.md +187 -0
- package/skills/lark-slides/references/lark-slides-xml-presentations-get.md +98 -0
- package/skills/lark-slides/references/planning-layer.md +219 -0
- package/skills/lark-slides/references/slide-templates.md +201 -0
- package/skills/lark-slides/references/slides_demo.xml +226 -0
- package/skills/lark-slides/references/slides_xml_schema_definition.xml +3049 -0
- package/skills/lark-slides/references/template-catalog.md +463 -0
- package/skills/lark-slides/references/template-index.json +1853 -0
- package/skills/lark-slides/references/troubleshooting.md +63 -0
- package/skills/lark-slides/references/validation-checklist.md +110 -0
- package/skills/lark-slides/references/visual-planning.md +254 -0
- package/skills/lark-slides/references/xml-format-guide.md +369 -0
- package/skills/lark-slides/references/xml-schema-quick-ref.md +245 -0
- package/skills/lark-slides/scripts/iconpark_tool.py +362 -0
- package/skills/lark-slides/scripts/iconpark_tool_test.py +177 -0
- package/skills/lark-slides/scripts/template_tool.py +970 -0
- package/skills/lark-slides/scripts/template_tool_test.py +177 -0
- package/skills/lark-slides/scripts/xml_text_overlap_lint.py +367 -0
- package/skills/lark-slides/scripts/xml_text_overlap_lint_test.py +263 -0
- package/skills/lark-task/SKILL.md +167 -0
- package/skills/lark-task/references/lark-task-assign.md +38 -0
- package/skills/lark-task/references/lark-task-comment.md +28 -0
- package/skills/lark-task/references/lark-task-complete.md +27 -0
- package/skills/lark-task/references/lark-task-create.md +57 -0
- package/skills/lark-task/references/lark-task-followers.md +35 -0
- package/skills/lark-task/references/lark-task-get-my-tasks.md +61 -0
- package/skills/lark-task/references/lark-task-get-related-tasks.md +53 -0
- package/skills/lark-task/references/lark-task-reminder.md +36 -0
- package/skills/lark-task/references/lark-task-reopen.md +27 -0
- package/skills/lark-task/references/lark-task-search.md +41 -0
- package/skills/lark-task/references/lark-task-set-ancestor.md +32 -0
- package/skills/lark-task/references/lark-task-tasklist-create.md +35 -0
- package/skills/lark-task/references/lark-task-tasklist-members.md +36 -0
- package/skills/lark-task/references/lark-task-tasklist-search.md +38 -0
- package/skills/lark-task/references/lark-task-tasklist-task-add.md +38 -0
- package/skills/lark-task/references/lark-task-update.md +37 -0
- package/skills/lark-task/references/lark-task-upload-attachment.md +59 -0
- package/skills/lark-vc/SKILL.md +202 -0
- package/skills/lark-vc/references/lark-vc-detail.md +44 -0
- package/skills/lark-vc/references/lark-vc-recording.md +154 -0
- package/skills/lark-vc/references/lark-vc-search.md +163 -0
- package/skills/lark-vc/references/vc-domain-boundaries.md +188 -0
- package/skills/lark-vc-agent/SKILL.md +169 -0
- package/skills/lark-vc-agent/references/lark-vc-agent-meeting-events.md +287 -0
- package/skills/lark-vc-agent/references/lark-vc-agent-meeting-join.md +141 -0
- package/skills/lark-vc-agent/references/lark-vc-agent-meeting-leave.md +105 -0
- package/skills/lark-vc-agent/references/lark-vc-agent-meeting-list-active.md +91 -0
- package/skills/lark-whiteboard/SKILL.md +47 -0
- package/skills/lark-whiteboard/elements/connectors.md +102 -0
- package/skills/lark-whiteboard/elements/content.md +40 -0
- package/skills/lark-whiteboard/elements/image.md +80 -0
- package/skills/lark-whiteboard/elements/layout.md +374 -0
- package/skills/lark-whiteboard/elements/schema.md +357 -0
- package/skills/lark-whiteboard/elements/style.md +318 -0
- package/skills/lark-whiteboard/elements/typography.md +73 -0
- package/skills/lark-whiteboard/references/lark-whiteboard-query.md +60 -0
- package/skills/lark-whiteboard/references/lark-whiteboard-update.md +122 -0
- package/skills/lark-whiteboard/references/lark-whiteboard-workflow.md +94 -0
- package/skills/lark-whiteboard/routes/dsl.md +107 -0
- package/skills/lark-whiteboard/routes/mermaid.md +27 -0
- package/skills/lark-whiteboard/routes/svg-edit.md +85 -0
- package/skills/lark-whiteboard/routes/svg.md +54 -0
- package/skills/lark-whiteboard/scenes/architecture.md +433 -0
- package/skills/lark-whiteboard/scenes/bar-chart.md +187 -0
- package/skills/lark-whiteboard/scenes/comparison.md +135 -0
- package/skills/lark-whiteboard/scenes/fishbone.md +238 -0
- package/skills/lark-whiteboard/scenes/flowchart.md +185 -0
- package/skills/lark-whiteboard/scenes/flywheel.md +195 -0
- package/skills/lark-whiteboard/scenes/funnel.md +101 -0
- package/skills/lark-whiteboard/scenes/line-chart.md +214 -0
- package/skills/lark-whiteboard/scenes/mermaid.md +130 -0
- package/skills/lark-whiteboard/scenes/milestone.md +139 -0
- package/skills/lark-whiteboard/scenes/organization.md +173 -0
- package/skills/lark-whiteboard/scenes/photo-showcase.md +126 -0
- package/skills/lark-whiteboard/scenes/pyramid.md +99 -0
- package/skills/lark-whiteboard/scenes/swimlane.md +371 -0
- package/skills/lark-whiteboard/scenes/treemap.md +216 -0
- package/skills/lark-wiki/SKILL.md +110 -0
- package/skills/lark-wiki/references/lark-wiki-delete-space.md +205 -0
- package/skills/lark-wiki/references/lark-wiki-member-add.md +67 -0
- package/skills/lark-wiki/references/lark-wiki-member-list.md +76 -0
- package/skills/lark-wiki/references/lark-wiki-member-remove.md +61 -0
- package/skills/lark-wiki/references/lark-wiki-move.md +183 -0
- package/skills/lark-wiki/references/lark-wiki-node-copy.md +72 -0
- package/skills/lark-wiki/references/lark-wiki-node-create.md +127 -0
- package/skills/lark-wiki/references/lark-wiki-node-delete.md +62 -0
- package/skills/lark-wiki/references/lark-wiki-node-get.md +57 -0
- package/skills/lark-wiki/references/lark-wiki-node-list.md +88 -0
- package/skills/lark-wiki/references/lark-wiki-space-create.md +46 -0
- package/skills/lark-wiki/references/lark-wiki-space-list.md +68 -0
- package/skills/lark-workflow-meeting-summary/SKILL.md +122 -0
- package/skills/lark-workflow-standup-report/SKILL.md +122 -0
|
@@ -0,0 +1,362 @@
|
|
|
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
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
SKILL_ROOT = Path(__file__).resolve().parent.parent
|
|
15
|
+
REFERENCES_DIR = SKILL_ROOT / "references"
|
|
16
|
+
DEFAULT_INDEX_PATH = REFERENCES_DIR / "iconpark-index.json"
|
|
17
|
+
DEFAULT_LIMIT = 8
|
|
18
|
+
CURATED_ICON_BOOSTS = {
|
|
19
|
+
"设置": {"iconpark/Base/setting.svg"},
|
|
20
|
+
"配置": {"iconpark/Base/setting.svg", "iconpark/Base/config.svg"},
|
|
21
|
+
"目标": {"iconpark/Base/aiming.svg", "iconpark/Sports/target-one.svg"},
|
|
22
|
+
"增长": {"iconpark/Charts/positive-dynamics.svg"},
|
|
23
|
+
"趋势": {"iconpark/Charts/chart-line.svg", "iconpark/Charts/positive-dynamics.svg"},
|
|
24
|
+
"占比": {"iconpark/Charts/chart-proportion.svg"},
|
|
25
|
+
"数据": {"iconpark/Charts/data-screen.svg"},
|
|
26
|
+
"看板": {"iconpark/Charts/data-screen.svg"},
|
|
27
|
+
"成功": {"iconpark/Character/check-one.svg"},
|
|
28
|
+
"完成": {"iconpark/Character/check-one.svg"},
|
|
29
|
+
"失败": {"iconpark/Character/close-one.svg"},
|
|
30
|
+
"风险": {"iconpark/Character/close-one.svg"},
|
|
31
|
+
"团队": {"iconpark/Peoples/peoples.svg"},
|
|
32
|
+
"用户": {"iconpark/Peoples/peoples.svg", "iconpark/Peoples/user.svg"},
|
|
33
|
+
"安全": {"iconpark/Safe/protect.svg"},
|
|
34
|
+
"防护": {"iconpark/Safe/protect.svg"},
|
|
35
|
+
"全球": {"iconpark/Travel/world.svg"},
|
|
36
|
+
"市场": {"iconpark/Travel/world.svg"},
|
|
37
|
+
"邮件": {"iconpark/Office/envelope-one.svg"},
|
|
38
|
+
"联系": {"iconpark/Office/envelope-one.svg"},
|
|
39
|
+
"会议": {"iconpark/Office/schedule.svg"},
|
|
40
|
+
"日程": {"iconpark/Office/schedule.svg"},
|
|
41
|
+
"飞书": {"iconpark/Brand/bydesign.svg"},
|
|
42
|
+
}
|
|
43
|
+
CURATED_BOOST_SCORE = 40
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class IconParkToolError(Exception):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def fail(message: str) -> None:
|
|
51
|
+
raise IconParkToolError(message)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def normalize_whitespace(value: str) -> str:
|
|
55
|
+
return re.sub(r"\s+", " ", value).strip()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def normalize_token(value: str) -> str:
|
|
59
|
+
return normalize_whitespace(value.lower().replace("_", "-"))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def append_unique(target: list[str], token: str) -> None:
|
|
63
|
+
normalized = normalize_token(token)
|
|
64
|
+
if normalized and normalized not in target:
|
|
65
|
+
target.append(normalized)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def tokenize_query(value: str) -> list[str]:
|
|
69
|
+
normalized = normalize_token(value)
|
|
70
|
+
if not normalized:
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
tokens: list[str] = []
|
|
74
|
+
for item in re.split(r"[\s,/|,。;;::()()【】\[\]《》<>]+", normalized):
|
|
75
|
+
append_unique(tokens, item)
|
|
76
|
+
|
|
77
|
+
for phrase in re.findall(r"[\u3400-\u9fff]+", normalized):
|
|
78
|
+
if len(phrase) < 2:
|
|
79
|
+
continue
|
|
80
|
+
max_size = min(6, len(phrase))
|
|
81
|
+
for size in range(max_size, 1, -1):
|
|
82
|
+
for start in range(0, len(phrase) - size + 1):
|
|
83
|
+
append_unique(tokens, phrase[start : start + size])
|
|
84
|
+
|
|
85
|
+
synonym_tokens = {
|
|
86
|
+
"目标": ["aim", "target", "goal"],
|
|
87
|
+
"聚焦": ["focus", "target"],
|
|
88
|
+
"增长": ["growth", "trend", "positive"],
|
|
89
|
+
"趋势": ["trend", "chart", "line"],
|
|
90
|
+
"数据": ["data", "analytics", "chart"],
|
|
91
|
+
"指标": ["metric", "data"],
|
|
92
|
+
"看板": ["dashboard", "screen", "data"],
|
|
93
|
+
"成功": ["success", "check", "done"],
|
|
94
|
+
"完成": ["done", "success", "check"],
|
|
95
|
+
"失败": ["fail", "close", "risk"],
|
|
96
|
+
"风险": ["risk", "fail", "protect"],
|
|
97
|
+
"安全": ["safe", "security", "protect"],
|
|
98
|
+
"配置": ["config", "setting", "system"],
|
|
99
|
+
"设置": ["setting", "config"],
|
|
100
|
+
"团队": ["team", "people", "users"],
|
|
101
|
+
"用户": ["user", "people"],
|
|
102
|
+
"全球": ["global", "world", "earth"],
|
|
103
|
+
"市场": ["market", "world", "business"],
|
|
104
|
+
"邮件": ["mail", "message"],
|
|
105
|
+
"mail": ["message", "envelope", "envelope-one"],
|
|
106
|
+
"计划": ["plan", "schedule"],
|
|
107
|
+
"时间": ["time", "schedule"],
|
|
108
|
+
"学习": ["learning", "education", "book"],
|
|
109
|
+
"培训": ["training", "education"],
|
|
110
|
+
"自动化": ["automation", "ai"],
|
|
111
|
+
"ai": ["ai", "automation", "magic"],
|
|
112
|
+
}
|
|
113
|
+
for token in list(tokens):
|
|
114
|
+
for keyword, aliases in synonym_tokens.items():
|
|
115
|
+
if is_ascii_token(keyword):
|
|
116
|
+
matches = token == keyword
|
|
117
|
+
else:
|
|
118
|
+
matches = keyword in token
|
|
119
|
+
if matches:
|
|
120
|
+
for alias in aliases:
|
|
121
|
+
append_unique(tokens, alias)
|
|
122
|
+
|
|
123
|
+
return tokens
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def is_ascii_token(value: str) -> bool:
|
|
127
|
+
return bool(re.fullmatch(r"[a-z0-9-]+", value))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def allows_substring_match(value: str) -> bool:
|
|
131
|
+
return not is_ascii_token(value) or len(value) >= 3
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def field_tokens(*values: str) -> set[str]:
|
|
135
|
+
tokens: set[str] = set()
|
|
136
|
+
for value in values:
|
|
137
|
+
normalized = normalize_token(value)
|
|
138
|
+
if not normalized:
|
|
139
|
+
continue
|
|
140
|
+
tokens.add(normalized)
|
|
141
|
+
for part in re.split(r"[-\s]+", normalized):
|
|
142
|
+
if part:
|
|
143
|
+
tokens.add(part)
|
|
144
|
+
return tokens
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def load_index(path: str | Path = DEFAULT_INDEX_PATH) -> dict[str, Any]:
|
|
148
|
+
index_path = Path(path)
|
|
149
|
+
if not index_path.exists():
|
|
150
|
+
fail(f"iconpark index not found: {index_path}")
|
|
151
|
+
try:
|
|
152
|
+
index_data = json.loads(index_path.read_text(encoding="utf-8"))
|
|
153
|
+
except json.JSONDecodeError as error:
|
|
154
|
+
fail(f"invalid iconpark index JSON: {error}")
|
|
155
|
+
if not isinstance(index_data.get("icons"), list):
|
|
156
|
+
fail("iconpark index must contain an icons array")
|
|
157
|
+
return index_data
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def icon_search_text(entry: dict[str, Any]) -> str:
|
|
161
|
+
parts = [
|
|
162
|
+
entry.get("iconType", ""),
|
|
163
|
+
entry.get("category", ""),
|
|
164
|
+
entry.get("name", ""),
|
|
165
|
+
" ".join(entry.get("tags") or []),
|
|
166
|
+
]
|
|
167
|
+
return normalize_token(" ".join(parts))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def score_icon(entry: dict[str, Any], query: str, tokens: list[str]) -> int:
|
|
171
|
+
raw_icon_type = entry.get("iconType", "")
|
|
172
|
+
icon_type = normalize_token(raw_icon_type)
|
|
173
|
+
category = normalize_token(entry.get("category", ""))
|
|
174
|
+
name = normalize_token(entry.get("name", ""))
|
|
175
|
+
tags = [normalize_token(tag) for tag in entry.get("tags") or []]
|
|
176
|
+
name_tokens = field_tokens(name)
|
|
177
|
+
category_tokens = field_tokens(category)
|
|
178
|
+
tag_tokens = field_tokens(*tags)
|
|
179
|
+
icon_type_tokens = field_tokens(icon_type)
|
|
180
|
+
search_text = icon_search_text(entry)
|
|
181
|
+
normalized_query = normalize_token(query)
|
|
182
|
+
|
|
183
|
+
score = 0
|
|
184
|
+
boosted_keywords: set[str] = set()
|
|
185
|
+
if normalized_query:
|
|
186
|
+
if normalized_query == icon_type or normalized_query == name:
|
|
187
|
+
score += 200
|
|
188
|
+
elif normalized_query in tag_tokens:
|
|
189
|
+
score += 120
|
|
190
|
+
elif normalized_query in icon_type_tokens:
|
|
191
|
+
score += 60
|
|
192
|
+
elif allows_substring_match(normalized_query) and normalized_query in search_text:
|
|
193
|
+
score += 30
|
|
194
|
+
|
|
195
|
+
for token in tokens:
|
|
196
|
+
for keyword, boosted_icon_types in CURATED_ICON_BOOSTS.items():
|
|
197
|
+
if keyword in boosted_keywords:
|
|
198
|
+
continue
|
|
199
|
+
if keyword in token and raw_icon_type in boosted_icon_types:
|
|
200
|
+
score += CURATED_BOOST_SCORE
|
|
201
|
+
boosted_keywords.add(keyword)
|
|
202
|
+
if token == name:
|
|
203
|
+
score += 80
|
|
204
|
+
elif token in name_tokens:
|
|
205
|
+
score += 55
|
|
206
|
+
elif allows_substring_match(token) and token in name:
|
|
207
|
+
score += 45
|
|
208
|
+
if token == category:
|
|
209
|
+
score += 35
|
|
210
|
+
elif token in category_tokens:
|
|
211
|
+
score += 25
|
|
212
|
+
elif allows_substring_match(token) and token in category:
|
|
213
|
+
score += 15
|
|
214
|
+
for tag in tags:
|
|
215
|
+
if token == tag:
|
|
216
|
+
score += 60
|
|
217
|
+
elif token in field_tokens(tag):
|
|
218
|
+
score += 45
|
|
219
|
+
elif allows_substring_match(token) and token in tag:
|
|
220
|
+
score += 20
|
|
221
|
+
if token in icon_type_tokens:
|
|
222
|
+
score += 20
|
|
223
|
+
elif allows_substring_match(token) and token in icon_type:
|
|
224
|
+
score += 15
|
|
225
|
+
|
|
226
|
+
return score
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def parse_limit(value: Any) -> int:
|
|
230
|
+
if value is None or value is False:
|
|
231
|
+
return DEFAULT_LIMIT
|
|
232
|
+
if value is True:
|
|
233
|
+
fail("limit requires an integer value")
|
|
234
|
+
try:
|
|
235
|
+
return int(value)
|
|
236
|
+
except (TypeError, ValueError):
|
|
237
|
+
fail(f"limit must be an integer: {value}")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def public_icon(entry: dict[str, Any], score: int | None = None) -> dict[str, Any]:
|
|
241
|
+
result = {
|
|
242
|
+
"iconType": entry["iconType"],
|
|
243
|
+
"category": entry["category"],
|
|
244
|
+
"name": entry["name"],
|
|
245
|
+
"tags": entry.get("tags") or [],
|
|
246
|
+
}
|
|
247
|
+
if score is not None:
|
|
248
|
+
result["score"] = score
|
|
249
|
+
return result
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def search_icons(index_data: dict[str, Any], options: dict[str, Any]) -> list[dict[str, Any]]:
|
|
253
|
+
query = str(options.get("query") or "")
|
|
254
|
+
if not normalize_whitespace(query):
|
|
255
|
+
fail("query is required")
|
|
256
|
+
limit = parse_limit(options.get("limit"))
|
|
257
|
+
category_filter = normalize_token(str(options.get("category") or ""))
|
|
258
|
+
tokens = tokenize_query(query)
|
|
259
|
+
|
|
260
|
+
ranked: list[dict[str, Any]] = []
|
|
261
|
+
for entry in index_data["icons"]:
|
|
262
|
+
if category_filter and normalize_token(entry.get("category", "")) != category_filter:
|
|
263
|
+
continue
|
|
264
|
+
score = score_icon(entry, query, tokens)
|
|
265
|
+
if query and score == 0:
|
|
266
|
+
continue
|
|
267
|
+
ranked.append(public_icon(entry, score))
|
|
268
|
+
|
|
269
|
+
ranked.sort(key=lambda item: (-int(item["score"]), item["category"], item["name"]))
|
|
270
|
+
return ranked[: max(limit, 0)]
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def resolve_icon(index_data: dict[str, Any], name_or_type: str | None) -> dict[str, Any]:
|
|
274
|
+
if not name_or_type:
|
|
275
|
+
fail("name is required")
|
|
276
|
+
target = normalize_token(name_or_type)
|
|
277
|
+
matches = []
|
|
278
|
+
for entry in index_data["icons"]:
|
|
279
|
+
candidates = {
|
|
280
|
+
normalize_token(entry["iconType"]),
|
|
281
|
+
normalize_token(entry["name"]),
|
|
282
|
+
normalize_token(f'{entry["category"]}/{entry["name"]}.svg'),
|
|
283
|
+
}
|
|
284
|
+
if target in candidates:
|
|
285
|
+
matches.append(entry)
|
|
286
|
+
if not matches:
|
|
287
|
+
fail(f"icon not found: {name_or_type}")
|
|
288
|
+
if len(matches) > 1:
|
|
289
|
+
names = ", ".join(entry["iconType"] for entry in matches)
|
|
290
|
+
fail(f"ambiguous icon name: {name_or_type}; matches: {names}")
|
|
291
|
+
return public_icon(matches[0])
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def list_categories(index_data: dict[str, Any]) -> list[dict[str, Any]]:
|
|
295
|
+
counts: dict[str, int] = {}
|
|
296
|
+
for entry in index_data["icons"]:
|
|
297
|
+
counts[entry["category"]] = counts.get(entry["category"], 0) + 1
|
|
298
|
+
return [{"category": category, "count": counts[category]} for category in sorted(counts)]
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def parse_cli_args(argv: list[str]) -> tuple[str | None, dict[str, Any]]:
|
|
302
|
+
if not argv:
|
|
303
|
+
return None, {}
|
|
304
|
+
command, *rest = argv
|
|
305
|
+
options: dict[str, Any] = {}
|
|
306
|
+
index = 0
|
|
307
|
+
while index < len(rest):
|
|
308
|
+
token = rest[index]
|
|
309
|
+
if not token.startswith("--"):
|
|
310
|
+
fail(f"unexpected argument: {token}")
|
|
311
|
+
key = token[2:]
|
|
312
|
+
next_token = rest[index + 1] if index + 1 < len(rest) else None
|
|
313
|
+
if next_token is None or next_token.startswith("--"):
|
|
314
|
+
options[key] = True
|
|
315
|
+
index += 1
|
|
316
|
+
continue
|
|
317
|
+
options[key] = next_token
|
|
318
|
+
index += 2
|
|
319
|
+
return command, options
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def print_usage() -> None:
|
|
323
|
+
usage = [
|
|
324
|
+
"Usage:",
|
|
325
|
+
" python3 iconpark_tool.py search --query <text> [--category <Category>] [--limit 8]",
|
|
326
|
+
" python3 iconpark_tool.py resolve --name <name|iconType>",
|
|
327
|
+
" python3 iconpark_tool.py list-categories",
|
|
328
|
+
]
|
|
329
|
+
print("\n".join(usage), file=sys.stderr)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def write_json(value: Any) -> None:
|
|
333
|
+
print(json.dumps(value, ensure_ascii=False, indent=2))
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def run_cli(argv: list[str] | None = None) -> None:
|
|
337
|
+
command, options = parse_cli_args(argv or sys.argv[1:])
|
|
338
|
+
if not command or command in {"--help", "help"}:
|
|
339
|
+
print_usage()
|
|
340
|
+
raise SystemExit(0)
|
|
341
|
+
|
|
342
|
+
index_data = load_index()
|
|
343
|
+
if command == "search":
|
|
344
|
+
write_json(search_icons(index_data, options))
|
|
345
|
+
return
|
|
346
|
+
if command == "resolve":
|
|
347
|
+
write_json(resolve_icon(index_data, options.get("name")))
|
|
348
|
+
return
|
|
349
|
+
if command == "list-categories":
|
|
350
|
+
write_json(list_categories(index_data))
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
print_usage()
|
|
354
|
+
fail(f"unknown command: {command}")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
if __name__ == "__main__":
|
|
358
|
+
try:
|
|
359
|
+
run_cli()
|
|
360
|
+
except IconParkToolError as error:
|
|
361
|
+
print(f"iconpark-tool error: {error}", file=sys.stderr)
|
|
362
|
+
raise SystemExit(1) from error
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
import unittest
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import iconpark_tool
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
SCRIPT_PATH = Path(__file__).resolve().with_name("iconpark_tool.py")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IconParkToolTest(unittest.TestCase):
|
|
18
|
+
@classmethod
|
|
19
|
+
def setUpClass(cls) -> None:
|
|
20
|
+
cls.index_data = iconpark_tool.load_index()
|
|
21
|
+
|
|
22
|
+
def test_search_icons_finds_growth_trend(self) -> None:
|
|
23
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": "增长趋势", "limit": 5})
|
|
24
|
+
self.assertTrue(results)
|
|
25
|
+
self.assertTrue(
|
|
26
|
+
any(entry["iconType"] == "iconpark/Charts/positive-dynamics.svg" for entry in results)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def test_search_icons_supports_english_query(self) -> None:
|
|
30
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": "security protect", "limit": 3})
|
|
31
|
+
self.assertTrue(results)
|
|
32
|
+
self.assertEqual(results[0]["iconType"], "iconpark/Safe/protect.svg")
|
|
33
|
+
|
|
34
|
+
def test_search_icons_supports_category_filter(self) -> None:
|
|
35
|
+
results = iconpark_tool.search_icons(
|
|
36
|
+
self.index_data,
|
|
37
|
+
{"query": "data", "category": "Charts", "limit": 10},
|
|
38
|
+
)
|
|
39
|
+
self.assertTrue(results)
|
|
40
|
+
self.assertTrue(all(entry["category"] == "Charts" for entry in results))
|
|
41
|
+
|
|
42
|
+
def test_search_icons_does_not_expand_ai_inside_words(self) -> None:
|
|
43
|
+
mail_results = iconpark_tool.search_icons(self.index_data, {"query": "mail", "limit": 5})
|
|
44
|
+
self.assertEqual(mail_results[0]["iconType"], "iconpark/Office/envelope-one.svg")
|
|
45
|
+
self.assertNotEqual(mail_results[0]["iconType"], "iconpark/Others/magic.svg")
|
|
46
|
+
|
|
47
|
+
fail_results = iconpark_tool.search_icons(self.index_data, {"query": "fail", "limit": 5})
|
|
48
|
+
self.assertNotEqual(fail_results[0]["iconType"], "iconpark/Others/magic.svg")
|
|
49
|
+
|
|
50
|
+
def test_search_icons_supports_template_icon_queries(self) -> None:
|
|
51
|
+
cases = [
|
|
52
|
+
("arrow", "iconpark/Arrows/arrow-right.svg"),
|
|
53
|
+
("right", "iconpark/Arrows/right.svg"),
|
|
54
|
+
("PPT", "iconpark/Music/ppt.svg"),
|
|
55
|
+
("table", "iconpark/Office/table.svg"),
|
|
56
|
+
("会议", "iconpark/Office/schedule.svg"),
|
|
57
|
+
("飞书", "iconpark/Brand/bydesign.svg"),
|
|
58
|
+
]
|
|
59
|
+
for query, icon_type in cases:
|
|
60
|
+
with self.subTest(query=query):
|
|
61
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": query, "limit": 10})
|
|
62
|
+
self.assertTrue(
|
|
63
|
+
any(entry["iconType"] == icon_type for entry in results),
|
|
64
|
+
f"{icon_type} not found in {results}",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def test_search_icons_defaults_to_wider_candidate_set(self) -> None:
|
|
68
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": "data"})
|
|
69
|
+
self.assertEqual(len(results), 8)
|
|
70
|
+
|
|
71
|
+
def test_search_icons_boosts_common_slide_terms(self) -> None:
|
|
72
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": "会议", "limit": 3})
|
|
73
|
+
self.assertTrue(
|
|
74
|
+
any(entry["iconType"] == "iconpark/Office/schedule.svg" for entry in results),
|
|
75
|
+
f"iconpark/Office/schedule.svg not found in {results}",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def test_search_icons_keeps_high_value_top_results(self) -> None:
|
|
79
|
+
cases = [
|
|
80
|
+
("安全", "iconpark/Safe/protect.svg"),
|
|
81
|
+
("邮件", "iconpark/Office/mail-open.svg"),
|
|
82
|
+
("会议", "iconpark/Office/schedule.svg"),
|
|
83
|
+
("增长趋势", "iconpark/Charts/chart-line.svg"),
|
|
84
|
+
("飞书", "iconpark/Brand/bydesign.svg"),
|
|
85
|
+
]
|
|
86
|
+
for query, icon_type in cases:
|
|
87
|
+
with self.subTest(query=query):
|
|
88
|
+
results = iconpark_tool.search_icons(self.index_data, {"query": query, "limit": 3})
|
|
89
|
+
self.assertTrue(results)
|
|
90
|
+
self.assertEqual(results[0]["iconType"], icon_type)
|
|
91
|
+
|
|
92
|
+
def test_search_icons_requires_query(self) -> None:
|
|
93
|
+
with self.assertRaises(iconpark_tool.IconParkToolError):
|
|
94
|
+
iconpark_tool.search_icons(self.index_data, {"limit": 5})
|
|
95
|
+
|
|
96
|
+
def test_search_icons_rejects_invalid_limit(self) -> None:
|
|
97
|
+
with self.assertRaises(iconpark_tool.IconParkToolError):
|
|
98
|
+
iconpark_tool.search_icons(self.index_data, {"query": "data", "limit": "abc"})
|
|
99
|
+
|
|
100
|
+
def test_resolve_icon_accepts_name_and_icon_type(self) -> None:
|
|
101
|
+
by_name = iconpark_tool.resolve_icon(self.index_data, "chart-line")
|
|
102
|
+
by_type = iconpark_tool.resolve_icon(self.index_data, "iconpark/Charts/chart-line.svg")
|
|
103
|
+
self.assertEqual(by_name["iconType"], "iconpark/Charts/chart-line.svg")
|
|
104
|
+
self.assertEqual(by_name, by_type)
|
|
105
|
+
|
|
106
|
+
def test_resolve_icon_accepts_template_icon_type(self) -> None:
|
|
107
|
+
result = iconpark_tool.resolve_icon(self.index_data, "iconpark/Arrows/arrow-right.svg")
|
|
108
|
+
self.assertEqual(result["iconType"], "iconpark/Arrows/arrow-right.svg")
|
|
109
|
+
|
|
110
|
+
def test_resolve_icon_rejects_unknown_name(self) -> None:
|
|
111
|
+
with self.assertRaises(iconpark_tool.IconParkToolError):
|
|
112
|
+
iconpark_tool.resolve_icon(self.index_data, "not-a-real-icon")
|
|
113
|
+
|
|
114
|
+
def test_list_categories_counts_index(self) -> None:
|
|
115
|
+
categories = iconpark_tool.list_categories(self.index_data)
|
|
116
|
+
self.assertTrue(any(entry["category"] == "Charts" and entry["count"] > 0 for entry in categories))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class IconParkToolCLITest(unittest.TestCase):
|
|
120
|
+
def run_tool(self, *args: str) -> subprocess.CompletedProcess[str]:
|
|
121
|
+
return subprocess.run(
|
|
122
|
+
[sys.executable, str(SCRIPT_PATH), *args],
|
|
123
|
+
capture_output=True,
|
|
124
|
+
check=False,
|
|
125
|
+
text=True,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def test_cli_search_writes_json_to_stdout(self) -> None:
|
|
129
|
+
result = self.run_tool("search", "--query", "增长趋势", "--limit", "5")
|
|
130
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
131
|
+
self.assertEqual(result.stderr, "")
|
|
132
|
+
|
|
133
|
+
output = json.loads(result.stdout)
|
|
134
|
+
self.assertTrue(output)
|
|
135
|
+
self.assertTrue(
|
|
136
|
+
any(entry["iconType"] == "iconpark/Charts/positive-dynamics.svg" for entry in output)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def test_cli_resolve_writes_json_to_stdout(self) -> None:
|
|
140
|
+
result = self.run_tool("resolve", "--name", "chart-line")
|
|
141
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
142
|
+
self.assertEqual(result.stderr, "")
|
|
143
|
+
|
|
144
|
+
output = json.loads(result.stdout)
|
|
145
|
+
self.assertEqual(output["iconType"], "iconpark/Charts/chart-line.svg")
|
|
146
|
+
|
|
147
|
+
def test_cli_list_categories_writes_json_to_stdout(self) -> None:
|
|
148
|
+
result = self.run_tool("list-categories")
|
|
149
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
150
|
+
self.assertEqual(result.stderr, "")
|
|
151
|
+
|
|
152
|
+
output = json.loads(result.stdout)
|
|
153
|
+
self.assertTrue(any(entry["category"] == "Charts" and entry["count"] > 0 for entry in output))
|
|
154
|
+
|
|
155
|
+
def test_cli_help_writes_usage_to_stderr(self) -> None:
|
|
156
|
+
result = self.run_tool("--help")
|
|
157
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
158
|
+
self.assertEqual(result.stdout, "")
|
|
159
|
+
self.assertIn("Usage:", result.stderr)
|
|
160
|
+
self.assertIn("python3 iconpark_tool.py search", result.stderr)
|
|
161
|
+
|
|
162
|
+
def test_cli_invalid_argument_writes_error_to_stderr(self) -> None:
|
|
163
|
+
result = self.run_tool("search", "增长趋势")
|
|
164
|
+
self.assertEqual(result.returncode, 1)
|
|
165
|
+
self.assertEqual(result.stdout, "")
|
|
166
|
+
self.assertIn("iconpark-tool error: unexpected argument: 增长趋势", result.stderr)
|
|
167
|
+
|
|
168
|
+
def test_cli_unknown_command_writes_usage_and_error_to_stderr(self) -> None:
|
|
169
|
+
result = self.run_tool("unknown")
|
|
170
|
+
self.assertEqual(result.returncode, 1)
|
|
171
|
+
self.assertEqual(result.stdout, "")
|
|
172
|
+
self.assertIn("Usage:", result.stderr)
|
|
173
|
+
self.assertIn("iconpark-tool error: unknown command: unknown", result.stderr)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
unittest.main()
|