weaver-work-cli 0.1.1 → 0.1.4
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 +187 -76
- package/dist/cmd/setup/index.js +5 -5
- package/dist/cmd/skills/index.js +1 -1
- package/dist/core/hooks.js +7 -0
- package/dist/index.js +0 -0
- package/dist/internal/e10/auth/commands.js +160 -55
- package/dist/internal/e10/auth/crypto.js +7 -22
- package/dist/internal/e10/auth/session.js +1 -1
- package/dist/internal/e10/auth/xiaoe.js +268 -0
- package/dist/internal/e10/context.js +16 -2
- package/dist/internal/e10/index.js +1 -0
- package/dist/internal/e10/request-runtime.js +344 -0
- package/dist/internal/skills/install.js +48 -6
- package/dist/internal/skills/reader.js +27 -0
- package/dist/shortcuts/archive/continuation.js +70 -0
- package/dist/shortcuts/archive/errors.js +53 -0
- package/dist/shortcuts/archive/host.js +197 -0
- package/dist/shortcuts/archive/index.js +363 -0
- package/dist/shortcuts/archive/manifest.js +45 -0
- package/dist/shortcuts/archive/operations/archive-info.js +55 -0
- package/dist/shortcuts/archive/operations/borrow-car.js +146 -0
- package/dist/shortcuts/archive/operations/borrow-list.js +200 -0
- package/dist/shortcuts/archive/operations/confirm.js +46 -0
- package/dist/shortcuts/archive/operations/download.js +238 -0
- package/dist/shortcuts/archive/operations/flow-url.js +240 -0
- package/dist/shortcuts/archive/operations/fonds.js +95 -0
- package/dist/shortcuts/archive/operations/getPageUrl.js +137 -0
- package/dist/shortcuts/archive/operations/registry.js +43 -0
- package/dist/shortcuts/archive/operations/search.js +88 -0
- package/dist/shortcuts/archive/operations/shared.js +120 -0
- package/dist/shortcuts/archive/operations/types.js +23 -0
- package/dist/shortcuts/archive/operations/upload.js +182 -0
- package/dist/shortcuts/archive/operations.js +13 -0
- package/dist/shortcuts/archive/render/search-format.js +276 -0
- package/dist/shortcuts/archive/render/search-view.js +125 -0
- package/dist/shortcuts/asset/continuation.js +70 -0
- package/dist/shortcuts/asset/errors.js +67 -0
- package/dist/shortcuts/asset/host.js +438 -0
- package/dist/shortcuts/asset/index.js +255 -0
- package/dist/shortcuts/asset/manifest.js +471 -0
- package/dist/shortcuts/asset/operations/query.js +249 -0
- package/dist/shortcuts/asset/operations/registry.js +85 -0
- package/dist/shortcuts/asset/operations/shared.js +100 -0
- package/dist/shortcuts/asset/operations/type-cache.js +49 -0
- package/dist/shortcuts/asset/operations/types.js +1 -0
- package/dist/shortcuts/asset/operations/viewlink.js +117 -0
- package/dist/shortcuts/asset/operations/write.js +435 -0
- package/dist/shortcuts/asset/operations.js +9 -0
- package/dist/shortcuts/calendar/continuation.js +70 -0
- package/dist/shortcuts/calendar/errors.js +53 -0
- package/dist/shortcuts/calendar/host.js +148 -0
- package/dist/shortcuts/calendar/index.js +125 -0
- package/dist/shortcuts/calendar/manifest.js +26 -0
- package/dist/shortcuts/calendar/operations/read.js +259 -0
- package/dist/shortcuts/calendar/operations/registry.js +31 -0
- package/dist/shortcuts/calendar/operations/shared.js +132 -0
- package/dist/shortcuts/calendar/operations/types.js +25 -0
- package/dist/shortcuts/calendar/operations/write.js +439 -0
- package/dist/shortcuts/calendar/operations.js +8 -0
- package/dist/shortcuts/ehr/continuation.js +70 -0
- package/dist/shortcuts/ehr/errors.js +53 -0
- package/dist/shortcuts/ehr/host.js +213 -0
- package/dist/shortcuts/ehr/index.js +205 -0
- package/dist/shortcuts/ehr/manifest.js +47 -0
- package/dist/shortcuts/ehr/operations/attend-read.js +373 -0
- package/dist/shortcuts/ehr/operations/attend-write.js +514 -0
- package/dist/shortcuts/ehr/operations/hr-contact.js +363 -0
- package/dist/shortcuts/ehr/operations/hr-ds.js +298 -0
- package/dist/shortcuts/ehr/operations/hr-report.js +386 -0
- package/dist/shortcuts/ehr/operations/recruit-write.js +1629 -0
- package/dist/shortcuts/ehr/operations/recruit.js +803 -0
- package/dist/shortcuts/ehr/operations/registry.js +43 -0
- package/dist/shortcuts/ehr/operations/salary.js +319 -0
- package/dist/shortcuts/ehr/operations/shared.js +246 -0
- package/dist/shortcuts/ehr/operations/types.js +25 -0
- package/dist/shortcuts/ehr/operations.js +25 -0
- package/dist/shortcuts/esb/continuation.js +70 -0
- package/dist/shortcuts/esb/errors.js +65 -0
- package/dist/shortcuts/esb/host.js +187 -0
- package/dist/shortcuts/esb/index.js +112 -0
- package/dist/shortcuts/esb/manifest.js +91 -0
- package/dist/shortcuts/esb/operations/input-format.js +31 -0
- package/dist/shortcuts/esb/operations/registry.js +48 -0
- package/dist/shortcuts/esb/operations/shared.js +152 -0
- package/dist/shortcuts/esb/operations/trigger.js +76 -0
- package/dist/shortcuts/esb/operations/types.js +21 -0
- package/dist/shortcuts/esb/operations.js +15 -0
- package/dist/shortcuts/fna/continuation.js +70 -0
- package/dist/shortcuts/fna/errors.js +59 -0
- package/dist/shortcuts/fna/host.js +146 -0
- package/dist/shortcuts/fna/index.js +111 -0
- package/dist/shortcuts/fna/manifest.js +41 -0
- package/dist/shortcuts/fna/operations/budget.js +124 -0
- package/dist/shortcuts/fna/operations/expense-center.js +148 -0
- package/dist/shortcuts/fna/operations/invoice-writeoff.js +212 -0
- package/dist/shortcuts/fna/operations/loan.js +195 -0
- package/dist/shortcuts/fna/operations/registry.js +35 -0
- package/dist/shortcuts/fna/operations/shared.js +210 -0
- package/dist/shortcuts/fna/operations/types.js +25 -0
- package/dist/shortcuts/fna/operations.js +19 -0
- package/dist/shortcuts/hrm/errors.js +38 -0
- package/dist/shortcuts/hrm/host.js +156 -0
- package/dist/shortcuts/hrm/index.js +111 -0
- package/dist/shortcuts/hrm/manifest.js +32 -0
- package/dist/shortcuts/hrm/operations/employee.js +338 -0
- package/dist/shortcuts/hrm/operations/org.js +110 -0
- package/dist/shortcuts/hrm/operations/position.js +176 -0
- package/dist/shortcuts/hrm/operations/registry.js +33 -0
- package/dist/shortcuts/hrm/operations/shared.js +143 -0
- package/dist/shortcuts/hrm/operations/types.js +23 -0
- package/dist/shortcuts/hrm/operations.js +19 -0
- package/dist/shortcuts/index.js +20 -0
- package/dist/shortcuts/invoice/host.js +99 -94
- package/dist/shortcuts/invoice/index.js +65 -61
- package/dist/shortcuts/invoice/manifest.js +222 -14
- package/dist/shortcuts/invoice/operations/browse-field.js +17 -0
- package/dist/shortcuts/invoice/operations/issuing.js +198 -0
- package/dist/shortcuts/invoice/operations/ocr-preview.js +6 -3
- package/dist/shortcuts/invoice/operations/registry.js +17 -0
- package/dist/shortcuts/invoice/operations/reim.js +401 -0
- package/dist/shortcuts/invoice/operations/shared.js +271 -6
- package/dist/shortcuts/invoice/operations/validate-preview.js +1 -1
- package/dist/shortcuts/jiuchuanhui/cache.js +441 -0
- package/dist/shortcuts/jiuchuanhui/continuation.js +70 -0
- package/dist/shortcuts/jiuchuanhui/errors.js +59 -0
- package/dist/shortcuts/jiuchuanhui/host.js +159 -0
- package/dist/shortcuts/jiuchuanhui/index.js +109 -0
- package/dist/shortcuts/jiuchuanhui/manifest.js +469 -0
- package/dist/shortcuts/jiuchuanhui/operations/datajson.js +214 -0
- package/dist/shortcuts/jiuchuanhui/operations/esb.js +157 -0
- package/dist/shortcuts/jiuchuanhui/operations/generic.js +146 -0
- package/dist/shortcuts/jiuchuanhui/operations/registry.js +133 -0
- package/dist/shortcuts/jiuchuanhui/operations/shared.js +158 -0
- package/dist/shortcuts/jiuchuanhui/operations/types.js +1 -0
- package/dist/shortcuts/jiuchuanhui/operations.js +8 -0
- package/dist/shortcuts/mail/continuation.js +70 -0
- package/dist/shortcuts/mail/errors.js +53 -0
- package/dist/shortcuts/mail/host.js +182 -0
- package/dist/shortcuts/mail/index.js +519 -0
- package/dist/shortcuts/mail/manifest.js +38 -0
- package/dist/shortcuts/mail/operations/mail-blacklist.js +79 -0
- package/dist/shortcuts/mail/operations/mail-contacts.js +195 -0
- package/dist/shortcuts/mail/operations/mail-manage.js +335 -0
- package/dist/shortcuts/mail/operations/mail-read.js +508 -0
- package/dist/shortcuts/mail/operations/mail-send.js +474 -0
- package/dist/shortcuts/mail/operations/mail-sign.js +203 -0
- package/dist/shortcuts/mail/operations/mail-template.js +170 -0
- package/dist/shortcuts/mail/operations/registry.js +41 -0
- package/dist/shortcuts/mail/operations/shared.js +64 -0
- package/dist/shortcuts/mail/operations/types.js +27 -0
- package/dist/shortcuts/mail/operations.js +19 -0
- package/dist/shortcuts/plan/continuation.js +70 -0
- package/dist/shortcuts/plan/errors.js +70 -0
- package/dist/shortcuts/plan/host.js +180 -0
- package/dist/shortcuts/plan/index.js +150 -0
- package/dist/shortcuts/plan/manifest.js +53 -0
- package/dist/shortcuts/plan/operations/link.js +256 -0
- package/dist/shortcuts/plan/operations/read.js +259 -0
- package/dist/shortcuts/plan/operations/registry.js +33 -0
- package/dist/shortcuts/plan/operations/shared.js +246 -0
- package/dist/shortcuts/plan/operations/types.js +49 -0
- package/dist/shortcuts/plan/operations/version.js +49 -0
- package/dist/shortcuts/plan/operations/write.js +710 -0
- package/dist/shortcuts/plan/operations.js +8 -0
- package/docs/SKILL.md +11 -7
- package/docs/_catalog.md +23 -5
- package/docs/agent-invoice.md +31 -10
- package/docs/agent-skill-install.md +211 -0
- package/docs/calendar.md +87 -0
- package/docs/e10-auth.md +28 -9
- package/docs/ehr.md +186 -0
- package/docs/esb.md +64 -0
- package/docs/fna.md +72 -0
- package/docs/hrm.md +89 -0
- package/docs/invoice.md +66 -20
- package/docs/jiuchuanhui.md +131 -0
- package/docs/operation-manual.md +443 -0
- package/docs/plan.md +82 -0
- package/docs/wenshuding.md +129 -0
- package/docs/ziguanjia.md +89 -0
- package/package.json +4 -4
- package/scripts/package-skill.mjs +127 -34
- package/scripts/postbuild.mjs +13 -0
- package/skill-template/business-info.json +13 -2
- package/skill-template/domains/calendar.md +15 -0
- package/skill-template/domains/esb.md +13 -0
- package/skill-template/domains/hrm.md +16 -0
- package/skill-template/domains/jiuchuanhui.md +23 -0
- package/skill-template/domains/jucailin.md +22 -0
- package/skill-template/domains/mail.md +21 -0
- package/skill-template/domains/plan.md +17 -0
- package/skill-template/domains/qiyecheng.md +17 -0
- package/skill-template/domains/shared.md +9 -3
- package/skill-template/domains/skill-maker.md +10 -0
- package/skill-template/domains/wenshuding.md +22 -0
- package/skill-template/domains/{invoice.md → yepiaotong.md} +4 -0
- package/skill-template/domains/ziguanjia.md +21 -0
- package/skill-template/master-skill-template.md +12 -6
- package/skill-template/skill-template.md +40 -9
- package/skills/weaver-e10-calendar/SKILL.md +101 -0
- package/skills/weaver-e10-calendar/product.json +8 -0
- package/skills/weaver-e10-calendar/references/calendar-app-check.md +65 -0
- package/skills/weaver-e10-calendar/references/calendar-dict.md +55 -0
- package/skills/weaver-e10-calendar/references/calendar-query.md +70 -0
- package/skills/weaver-e10-calendar/references/calendar-write.md +97 -0
- package/skills/weaver-e10-calendar/references/source-manifest.json +54 -0
- package/skills/weaver-e10-esb/SKILL.md +102 -0
- package/skills/weaver-e10-esb/product.json +8 -0
- package/skills/weaver-e10-esb/references/input-format.md +52 -0
- package/skills/weaver-e10-esb/references/source-manifest.json +242 -0
- package/skills/weaver-e10-esb/references/trigger.md +99 -0
- package/skills/weaver-e10-hrm/SKILL.md +87 -0
- package/skills/weaver-e10-hrm/product.json +8 -0
- package/skills/weaver-e10-hrm/references/employee.md +109 -0
- package/skills/weaver-e10-hrm/references/org.md +95 -0
- package/skills/weaver-e10-hrm/references/position.md +95 -0
- package/skills/weaver-e10-hrm/references/source-manifest.json +121 -0
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +174 -0
- package/skills/weaver-e10-jiuchuanhui/product.json +8 -0
- package/skills/weaver-e10-jiuchuanhui/references/cache.md +110 -0
- package/skills/weaver-e10-jiuchuanhui/references/clue.md +61 -0
- package/skills/weaver-e10-jiuchuanhui/references/contact-plan.md +56 -0
- package/skills/weaver-e10-jiuchuanhui/references/contact-records.md +48 -0
- package/skills/weaver-e10-jiuchuanhui/references/contact.md +56 -0
- package/skills/weaver-e10-jiuchuanhui/references/customer.md +69 -0
- package/skills/weaver-e10-jiuchuanhui/references/disabled-capabilities.md +24 -0
- package/skills/weaver-e10-jiuchuanhui/references/discovery-config.md +60 -0
- package/skills/weaver-e10-jiuchuanhui/references/general-helpers.md +59 -0
- package/skills/weaver-e10-jiuchuanhui/references/jiuchuanhui-entry.md +60 -0
- package/skills/weaver-e10-jiuchuanhui/references/sale.md +72 -0
- package/skills/weaver-e10-jiuchuanhui/references/source-manifest.json +2632 -0
- package/skills/weaver-e10-jucailin/SKILL.md +101 -0
- package/skills/weaver-e10-jucailin/product.json +8 -0
- package/skills/weaver-e10-jucailin/references/attend-read.md +73 -0
- package/skills/weaver-e10-jucailin/references/attend-write.md +82 -0
- package/skills/weaver-e10-jucailin/references/hr-contact.md +92 -0
- package/skills/weaver-e10-jucailin/references/hr-datasource.md +104 -0
- package/skills/weaver-e10-jucailin/references/hr-report.md +76 -0
- package/skills/weaver-e10-jucailin/references/recruit-read.md +76 -0
- package/skills/weaver-e10-jucailin/references/recruit-write.md +70 -0
- package/skills/weaver-e10-jucailin/references/safety-boundaries.md +35 -0
- package/skills/weaver-e10-jucailin/references/salary.md +110 -0
- package/skills/weaver-e10-jucailin/references/source-manifest.json +152 -0
- package/skills/weaver-e10-mail/SKILL.md +151 -0
- package/skills/weaver-e10-mail/product.json +8 -0
- package/skills/weaver-e10-mail/references/mail-agent-entry.md +47 -0
- package/skills/weaver-e10-mail/references/mail-attachment.md +30 -0
- package/skills/weaver-e10-mail/references/mail-blacklist.md +27 -0
- package/skills/weaver-e10-mail/references/mail-contacts.md +33 -0
- package/skills/weaver-e10-mail/references/mail-manage.md +44 -0
- package/skills/weaver-e10-mail/references/mail-read.md +76 -0
- package/skills/weaver-e10-mail/references/mail-send.md +43 -0
- package/skills/weaver-e10-mail/references/mail-sign.md +33 -0
- package/skills/weaver-e10-mail/references/mail-template.md +31 -0
- package/skills/weaver-e10-mail/references/safety-boundaries.md +32 -0
- package/skills/weaver-e10-plan/SKILL.md +139 -0
- package/skills/weaver-e10-plan/product.json +8 -0
- package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +123 -0
- package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +138 -0
- package/skills/weaver-e10-plan/references/plan-report-query.md +154 -0
- package/skills/weaver-e10-plan/references/plan-report-remind.md +104 -0
- package/skills/weaver-e10-plan/references/plan-report-write.md +162 -0
- package/skills/weaver-e10-plan/references/source-manifest.json +858 -0
- package/skills/weaver-e10-qiyecheng/SKILL.md +118 -0
- package/skills/weaver-e10-qiyecheng/product.json +8 -0
- package/skills/weaver-e10-qiyecheng/references/budget.md +65 -0
- package/skills/weaver-e10-qiyecheng/references/catalog.md +56 -0
- package/skills/weaver-e10-qiyecheng/references/expense-center.md +51 -0
- package/skills/weaver-e10-qiyecheng/references/invoice-writeoff.md +57 -0
- package/skills/weaver-e10-qiyecheng/references/loan-management.md +59 -0
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +698 -0
- package/skills/weaver-e10-shared/SKILL.md +86 -0
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +127 -0
- package/skills/weaver-e10-shared/references/json-output-contract.md +120 -0
- package/skills/weaver-e10-shared/references/weaver-e10-installation.md +110 -0
- package/skills/weaver-e10-skill-maker/SKILL.md +77 -0
- package/skills/weaver-e10-skill-maker/product.json +8 -0
- package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +124 -0
- package/skills/weaver-e10-skill-maker/references/detector-validation.md +101 -0
- package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +230 -0
- package/skills/weaver-e10-skill-maker/references/post-generation-install.md +105 -0
- package/skills/weaver-e10-skill-maker/references/source-update-detection.md +261 -0
- package/skills/weaver-e10-skill-maker/references/weaver-skill-style.md +141 -0
- package/skills/weaver-e10-wenshuding/SKILL.md +157 -0
- package/skills/weaver-e10-wenshuding/product.json +8 -0
- package/skills/weaver-e10-wenshuding/references/archive-agent-entry.md +63 -0
- package/skills/weaver-e10-wenshuding/references/archive-borrow-car.md +52 -0
- package/skills/weaver-e10-wenshuding/references/archive-borrow-list.md +52 -0
- package/skills/weaver-e10-wenshuding/references/archive-disabled-capabilities.md +22 -0
- package/skills/weaver-e10-wenshuding/references/archive-download.md +48 -0
- package/skills/weaver-e10-wenshuding/references/archive-flow.md +46 -0
- package/skills/weaver-e10-wenshuding/references/archive-fonds.md +34 -0
- package/skills/weaver-e10-wenshuding/references/archive-info.md +33 -0
- package/skills/weaver-e10-wenshuding/references/archive-search.md +52 -0
- package/skills/weaver-e10-wenshuding/references/archive-upload.md +41 -0
- package/skills/weaver-e10-wenshuding/references/source-manifest.json +517 -0
- package/skills/weaver-e10-yepiaotong/SKILL.md +184 -0
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-add.md +1 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +47 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-browse-field-data.md +204 -0
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-delete.md +1 -1
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-detail.md +13 -5
- package/skills/weaver-e10-yepiaotong/references/invoice-disabled-capabilities.md +28 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-download.md +31 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +45 -0
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-file-upload.md +15 -4
- package/skills/weaver-e10-yepiaotong/references/invoice-import.md +45 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +120 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-field-rules.md +161 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing.md +99 -0
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-ocr-preview.md +14 -4
- package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +58 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-red.md +261 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +97 -0
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-update.md +1 -1
- package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/references/invoice-validation-preview.md +10 -3
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +1340 -0
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +845 -0
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +94 -0
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +449 -0
- package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +266 -0
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +494 -0
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +1103 -0
- package/skills/weaver-e10-ziguanjia/SKILL.md +162 -0
- package/skills/weaver-e10-ziguanjia/product.json +8 -0
- package/skills/weaver-e10-ziguanjia/references/source-manifest.json +147 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +65 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-create.md +45 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-depre.md +48 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-disabled-capabilities.md +22 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-purch.md +57 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-query.md +62 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-repair.md +83 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-resolve.md +49 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-return.md +70 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-update.md +45 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-use.md +60 -0
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-viewlink.md +81 -0
- package/skills/weaver-work-cli-invoice/SKILL.md +0 -103
- package/skills/weaver-work-cli-invoice/references/invoice-agent-entry.md +0 -38
- package/skills/weaver-work-cli-invoice/references/invoice-disabled-capabilities.md +0 -26
- package/skills/weaver-work-cli-invoice/references/invoice-download.md +0 -22
- package/skills/weaver-work-cli-invoice/references/invoice-enterprise-list.md +0 -35
- package/skills/weaver-work-cli-invoice/references/invoice-import.md +0 -28
- package/skills/weaver-work-cli-invoice/references/invoice-personal-list.md +0 -47
- package/skills/weaver-work-cli-shared/SKILL.md +0 -53
- package/skills/weaver-work-cli-shared/references/e10-auth-and-session.md +0 -83
- package/skills/weaver-work-cli-shared/references/json-output-contract.md +0 -61
- package/skills/weaver-work-cli-shared/references/weaver-work-cli-installation.md +0 -61
- /package/skills/{weaver-work-cli-shared → weaver-e10-shared}/references/high-risk-write.md +0 -0
- /package/skills/{weaver-work-cli-invoice → weaver-e10-yepiaotong}/product.json +0 -0
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { CliError, ExitCode } from '../../core/errors.js';
|
|
2
2
|
import { E10AuthSession } from './auth/session.js';
|
|
3
|
+
import { hasXiaoEEnv, tryXiaoEUnifiedLogin } from './auth/xiaoe.js';
|
|
3
4
|
import { E10ApiClient } from './client.js';
|
|
5
|
+
function shouldPreferXiaoEUnifiedLogin(options, env) {
|
|
6
|
+
return hasXiaoEEnv(env) && !options.auth && !options.profile;
|
|
7
|
+
}
|
|
4
8
|
export async function getE10Session(ctx) {
|
|
5
|
-
|
|
9
|
+
const options = ctx.getGlobalOptions();
|
|
10
|
+
if (shouldPreferXiaoEUnifiedLogin(options, ctx.env)) {
|
|
11
|
+
const xiaoELogin = await tryXiaoEUnifiedLogin({
|
|
12
|
+
env: ctx.env,
|
|
13
|
+
baseUrl: options.baseUrl,
|
|
14
|
+
logger: ctx.logger,
|
|
15
|
+
});
|
|
16
|
+
if (xiaoELogin)
|
|
17
|
+
return xiaoELogin.session;
|
|
18
|
+
}
|
|
19
|
+
return E10AuthSession.fromOptions(options, ctx.cwd);
|
|
6
20
|
}
|
|
7
21
|
export async function requireE10Session(ctx) {
|
|
8
22
|
const session = await getE10Session(ctx);
|
|
9
23
|
if (!session) {
|
|
10
|
-
throw new CliError('E10 auth not found.
|
|
24
|
+
throw new CliError('E10 auth not found. In XiaoE, run weaver-work-cli auth xiaoe first; if unified login is unavailable, ask the user for the E10 login domain (base URL), then run: weaver-work-cli auth login --base-url <url> --agent_type <agent_type>.', ExitCode.AuthError);
|
|
11
25
|
}
|
|
12
26
|
return session;
|
|
13
27
|
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { CliError, ExitCode } from '../../core/errors.js';
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
const RESERVED_HEADERS = [
|
|
4
|
+
'authorization',
|
|
5
|
+
'cookie',
|
|
6
|
+
'eteamsid',
|
|
7
|
+
'token',
|
|
8
|
+
];
|
|
9
|
+
export class E10ApiError extends CliError {
|
|
10
|
+
type;
|
|
11
|
+
subtype;
|
|
12
|
+
code;
|
|
13
|
+
retryable;
|
|
14
|
+
details;
|
|
15
|
+
constructor(type, subtype, message, options = {}) {
|
|
16
|
+
super(message, options.exitCode ?? ExitCode.GeneralError);
|
|
17
|
+
this.name = 'E10ApiError';
|
|
18
|
+
this.type = type;
|
|
19
|
+
this.subtype = subtype;
|
|
20
|
+
this.code = options.code;
|
|
21
|
+
this.retryable = options.retryable ?? false;
|
|
22
|
+
this.details = options.details;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class E10RequestRuntime {
|
|
26
|
+
ctx;
|
|
27
|
+
session;
|
|
28
|
+
interceptors;
|
|
29
|
+
fetchFn;
|
|
30
|
+
constructor(ctx, session, dependencies = {}) {
|
|
31
|
+
this.ctx = ctx;
|
|
32
|
+
this.session = session;
|
|
33
|
+
this.fetchFn = dependencies.fetch || globalThis.fetch;
|
|
34
|
+
this.interceptors = [
|
|
35
|
+
...(this.ctx.hooks?.getE10RequestInterceptors?.() || []),
|
|
36
|
+
...(dependencies.interceptors || []),
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
async requestJson(request) {
|
|
40
|
+
return this.request({ ...request, responseType: 'json' });
|
|
41
|
+
}
|
|
42
|
+
async requestBinary(request) {
|
|
43
|
+
return this.request({ ...request, responseType: 'binary' });
|
|
44
|
+
}
|
|
45
|
+
async request(request) {
|
|
46
|
+
const mutable = this.prepareRequest(request);
|
|
47
|
+
const sessionContext = this.sessionContext();
|
|
48
|
+
try {
|
|
49
|
+
await this.runBeforeRequest(mutable, sessionContext);
|
|
50
|
+
this.assertPath(mutable.path);
|
|
51
|
+
if (mutable.path !== request.path) {
|
|
52
|
+
throw new E10ApiError('policy', 'path_rewrite_denied', 'E10 API 拦截器不能修改请求路径', {
|
|
53
|
+
exitCode: ExitCode.PolicyError,
|
|
54
|
+
details: { from: request.path, to: mutable.path },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
stripReservedHeaders(mutable.headers);
|
|
58
|
+
const url = withQuery(this.session.getBaseUrl(), mutable.path, mutable.query);
|
|
59
|
+
const headers = this.composeHeaders(mutable, request.trustedHeaders);
|
|
60
|
+
const init = this.buildFetchInit(mutable, headers);
|
|
61
|
+
const response = await this.fetchWithTimeout(url, init, mutable.timeoutMs);
|
|
62
|
+
const parsed = await this.readResponse(response, mutable.responseType, mutable.bigIntStrings);
|
|
63
|
+
await this.runAfterResponse(mutable, sessionContext, parsed);
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
await this.runOnError(mutable, sessionContext, error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
prepareRequest(request) {
|
|
72
|
+
return {
|
|
73
|
+
module: request.module,
|
|
74
|
+
operation: request.operation,
|
|
75
|
+
method: (request.method || 'POST').toUpperCase(),
|
|
76
|
+
path: request.path,
|
|
77
|
+
query: { ...(request.query || {}) },
|
|
78
|
+
headers: sanitizePublicHeaders(request.headers || {}),
|
|
79
|
+
body: request.body,
|
|
80
|
+
form: request.form,
|
|
81
|
+
formData: request.formData,
|
|
82
|
+
timeoutMs: request.timeoutMs || DEFAULT_TIMEOUT_MS,
|
|
83
|
+
responseType: request.responseType || 'json',
|
|
84
|
+
bigIntStrings: request.bigIntStrings === true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
sessionContext() {
|
|
88
|
+
return {
|
|
89
|
+
baseUrl: this.session.getBaseUrl(),
|
|
90
|
+
userId: this.session.userId,
|
|
91
|
+
agentType: this.session.agentType,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async runBeforeRequest(request, session) {
|
|
95
|
+
for (const interceptor of this.interceptors) {
|
|
96
|
+
await interceptor.beforeRequest?.({ request, session });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async runAfterResponse(request, session, response) {
|
|
100
|
+
for (const interceptor of this.interceptors) {
|
|
101
|
+
await interceptor.afterResponse?.({
|
|
102
|
+
request: requestForHook(request),
|
|
103
|
+
session,
|
|
104
|
+
response: responseForHook(response),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async runOnError(request, session, error) {
|
|
109
|
+
for (const interceptor of this.interceptors) {
|
|
110
|
+
await interceptor.onError?.({ request, session, error });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
assertPath(requestPath) {
|
|
114
|
+
if (typeof requestPath !== 'string' || !requestPath.startsWith('/') || requestPath.startsWith('//')) {
|
|
115
|
+
throw new E10ApiError('validation', 'path_invalid', '请求路径必须是相对绝对路径', {
|
|
116
|
+
exitCode: ExitCode.UsageError,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (/^https?:/i.test(requestPath) || /[\r\n]/.test(requestPath) || requestPath.includes('/../')) {
|
|
120
|
+
throw new E10ApiError('validation', 'path_invalid', '请求路径不允许跨域或路径逃逸', {
|
|
121
|
+
exitCode: ExitCode.UsageError,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!requestPath.startsWith('/api/')) {
|
|
125
|
+
throw new E10ApiError('validation', 'path_not_allowed', 'E10 API 只能调用 /api/ 路径', {
|
|
126
|
+
exitCode: ExitCode.UsageError,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
composeHeaders(request, trustedHeaders = {}) {
|
|
131
|
+
return {
|
|
132
|
+
Accept: 'application/json, text/plain, */*',
|
|
133
|
+
...request.headers,
|
|
134
|
+
Cookie: this.session.cookieHeader(),
|
|
135
|
+
eteamsid: this.session.eteamsId,
|
|
136
|
+
'User-Agent': this.session.uaHeader(),
|
|
137
|
+
Origin: this.session.getBaseUrl(),
|
|
138
|
+
'X-Weaver-Cli-Source': 'weaver-work-cli',
|
|
139
|
+
'X-Weaver-Cli-Version': this.ctx.packageInfo?.version || 'unknown',
|
|
140
|
+
...(request.module ? { 'X-Weaver-Cli-Module': request.module } : {}),
|
|
141
|
+
...(request.operation ? { 'X-Weaver-Cli-Operation': request.operation } : {}),
|
|
142
|
+
...trustedHeaders,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
buildFetchInit(request, headers) {
|
|
146
|
+
const init = {
|
|
147
|
+
method: request.method,
|
|
148
|
+
headers,
|
|
149
|
+
redirect: 'manual',
|
|
150
|
+
};
|
|
151
|
+
if (request.formData) {
|
|
152
|
+
init.body = request.formData;
|
|
153
|
+
}
|
|
154
|
+
else if (request.form !== undefined) {
|
|
155
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
156
|
+
init.body = String(request.form);
|
|
157
|
+
}
|
|
158
|
+
else if (request.body !== undefined) {
|
|
159
|
+
headers['Content-Type'] = 'application/json;charset=UTF-8';
|
|
160
|
+
init.body = JSON.stringify(request.body);
|
|
161
|
+
}
|
|
162
|
+
return init;
|
|
163
|
+
}
|
|
164
|
+
async fetchWithTimeout(url, init, timeoutMs) {
|
|
165
|
+
const controller = new AbortController();
|
|
166
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
167
|
+
try {
|
|
168
|
+
return await this.fetchFn(url, { ...init, signal: controller.signal });
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
172
|
+
throw new E10ApiError('network', 'timeout', `请求超时(${timeoutMs}ms)`, {
|
|
173
|
+
retryable: false,
|
|
174
|
+
exitCode: ExitCode.NetworkError,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
throw new E10ApiError('network', 'transport', `请求失败:${message}`, {
|
|
179
|
+
retryable: true,
|
|
180
|
+
exitCode: ExitCode.NetworkError,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async readResponse(response, responseType, bigIntStrings = false) {
|
|
188
|
+
if (responseType === 'binary') {
|
|
189
|
+
return {
|
|
190
|
+
status: response.status,
|
|
191
|
+
headers: response.headers,
|
|
192
|
+
content: Buffer.from(await response.arrayBuffer()),
|
|
193
|
+
contentType: response.headers.get('content-type') || 'application/octet-stream',
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const text = await response.text();
|
|
197
|
+
let value = {};
|
|
198
|
+
let parseError;
|
|
199
|
+
try {
|
|
200
|
+
value = text ? (bigIntStrings ? parseJsonPreservingBigInts(text) : JSON.parse(text)) : {};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
parseError = error instanceof Error ? error : new Error(String(error));
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
status: response.status,
|
|
207
|
+
headers: response.headers,
|
|
208
|
+
text,
|
|
209
|
+
value,
|
|
210
|
+
...(parseError ? { parseError } : {}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export function parseJsonPreservingBigInts(text) {
|
|
215
|
+
return JSON.parse(quoteLargeJsonIntegers(text));
|
|
216
|
+
}
|
|
217
|
+
function quoteLargeJsonIntegers(text) {
|
|
218
|
+
let output = '';
|
|
219
|
+
let i = 0;
|
|
220
|
+
let inString = false;
|
|
221
|
+
let escaped = false;
|
|
222
|
+
while (i < text.length) {
|
|
223
|
+
const char = text[i];
|
|
224
|
+
if (inString) {
|
|
225
|
+
output += char;
|
|
226
|
+
if (escaped) {
|
|
227
|
+
escaped = false;
|
|
228
|
+
}
|
|
229
|
+
else if (char === '\\') {
|
|
230
|
+
escaped = true;
|
|
231
|
+
}
|
|
232
|
+
else if (char === '"') {
|
|
233
|
+
inString = false;
|
|
234
|
+
}
|
|
235
|
+
i += 1;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (char === '"') {
|
|
239
|
+
inString = true;
|
|
240
|
+
output += char;
|
|
241
|
+
i += 1;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (char === '-' || (char >= '0' && char <= '9')) {
|
|
245
|
+
const start = i;
|
|
246
|
+
if (char === '-')
|
|
247
|
+
i += 1;
|
|
248
|
+
const digitStart = i;
|
|
249
|
+
while (i < text.length && text[i] >= '0' && text[i] <= '9')
|
|
250
|
+
i += 1;
|
|
251
|
+
if (digitStart === i) {
|
|
252
|
+
output += text.slice(start, i);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (text[i] === '.' || text[i] === 'e' || text[i] === 'E') {
|
|
256
|
+
if (text[i] === '.') {
|
|
257
|
+
i += 1;
|
|
258
|
+
while (i < text.length && text[i] >= '0' && text[i] <= '9')
|
|
259
|
+
i += 1;
|
|
260
|
+
}
|
|
261
|
+
if (text[i] === 'e' || text[i] === 'E') {
|
|
262
|
+
i += 1;
|
|
263
|
+
if (text[i] === '+' || text[i] === '-')
|
|
264
|
+
i += 1;
|
|
265
|
+
while (i < text.length && text[i] >= '0' && text[i] <= '9')
|
|
266
|
+
i += 1;
|
|
267
|
+
}
|
|
268
|
+
output += text.slice(start, i);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const rawNumber = text.slice(start, i);
|
|
272
|
+
const digitCount = rawNumber.startsWith('-') ? rawNumber.length - 1 : rawNumber.length;
|
|
273
|
+
output += digitCount >= 16 ? `"${rawNumber}"` : rawNumber;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
output += char;
|
|
277
|
+
i += 1;
|
|
278
|
+
}
|
|
279
|
+
return output;
|
|
280
|
+
}
|
|
281
|
+
export function createE10RequestRuntime(ctx, session, dependencies = {}) {
|
|
282
|
+
return new E10RequestRuntime(ctx, session, dependencies);
|
|
283
|
+
}
|
|
284
|
+
function withQuery(baseUrl, requestPath, query = {}) {
|
|
285
|
+
const url = new URL(`${baseUrl}${requestPath}`);
|
|
286
|
+
for (const [key, value] of Object.entries(query)) {
|
|
287
|
+
if (value === undefined || value === null)
|
|
288
|
+
continue;
|
|
289
|
+
if (Array.isArray(value)) {
|
|
290
|
+
for (const item of value)
|
|
291
|
+
url.searchParams.append(key, String(item));
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
url.searchParams.set(key, String(value));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return url;
|
|
298
|
+
}
|
|
299
|
+
function sanitizePublicHeaders(headers) {
|
|
300
|
+
const next = { ...headers };
|
|
301
|
+
stripReservedHeaders(next);
|
|
302
|
+
return next;
|
|
303
|
+
}
|
|
304
|
+
function stripReservedHeaders(headers) {
|
|
305
|
+
for (const key of Object.keys(headers)) {
|
|
306
|
+
if (RESERVED_HEADERS.includes(key.toLowerCase())) {
|
|
307
|
+
delete headers[key];
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function responseForHook(response) {
|
|
312
|
+
if ('content' in response) {
|
|
313
|
+
return {
|
|
314
|
+
status: response.status,
|
|
315
|
+
headers: new Headers(response.headers),
|
|
316
|
+
contentType: response.contentType,
|
|
317
|
+
contentLength: response.content.length,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
status: response.status,
|
|
322
|
+
headers: new Headers(response.headers),
|
|
323
|
+
value: cloneForHook(response.value),
|
|
324
|
+
text: response.text,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function requestForHook(request) {
|
|
328
|
+
return {
|
|
329
|
+
...request,
|
|
330
|
+
query: { ...request.query },
|
|
331
|
+
headers: { ...request.headers },
|
|
332
|
+
body: cloneForHook(request.body),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function cloneForHook(value) {
|
|
336
|
+
if (value === undefined || value === null)
|
|
337
|
+
return value;
|
|
338
|
+
try {
|
|
339
|
+
return structuredClone(value);
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return value;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { basename, relative, resolve, sep } from 'node:path';
|
|
4
|
-
const SKILL_PREFIX = 'weaver-
|
|
5
|
-
const
|
|
4
|
+
const SKILL_PREFIX = 'weaver-e10-';
|
|
5
|
+
const LEGACY_SKILL_PREFIX = 'weaver-work-cli-';
|
|
6
|
+
const SHARED_SKILL_NAME = 'weaver-e10-shared';
|
|
7
|
+
const LEGACY_SHARED_SKILL_NAME = 'weaver-work-cli-shared';
|
|
6
8
|
export function defaultCodexSkillsRoot(env = process.env) {
|
|
7
9
|
const codexHome = env.CODEX_HOME || resolve(homedir(), '.codex');
|
|
8
10
|
return resolve(codexHome, 'skills');
|
|
@@ -17,6 +19,9 @@ export function normalizePackagedSkillName(value) {
|
|
|
17
19
|
if (!/^[A-Za-z0-9._-]+$/u.test(trimmed)) {
|
|
18
20
|
throw new Error(`invalid skill name: ${value}`);
|
|
19
21
|
}
|
|
22
|
+
if (trimmed.startsWith(LEGACY_SKILL_PREFIX)) {
|
|
23
|
+
return `${SKILL_PREFIX}${trimmed.slice(LEGACY_SKILL_PREFIX.length)}`;
|
|
24
|
+
}
|
|
20
25
|
return trimmed.startsWith(SKILL_PREFIX) ? trimmed : `${SKILL_PREFIX}${trimmed}`;
|
|
21
26
|
}
|
|
22
27
|
export function resolvePackagedSkillNames(sourceRoot, requested = 'all') {
|
|
@@ -28,7 +33,13 @@ export function resolvePackagedSkillNames(sourceRoot, requested = 'all') {
|
|
|
28
33
|
if (!normalized || normalized === 'all')
|
|
29
34
|
return available;
|
|
30
35
|
if (!available.includes(normalized)) {
|
|
31
|
-
|
|
36
|
+
const shortName = normalized.slice(SKILL_PREFIX.length);
|
|
37
|
+
const suggestions = available.filter((name) => editDistance(shortName, name.replace(/^weaver-e10-/u, '')) <= 2);
|
|
38
|
+
throw new Error([
|
|
39
|
+
`unknown packaged skill: ${requested}`,
|
|
40
|
+
...(suggestions.length ? [`Did you mean: ${suggestions.join(', ')}?`] : []),
|
|
41
|
+
'Run "weaver-work-cli skills list" to see available skills.',
|
|
42
|
+
].join('\n'));
|
|
32
43
|
}
|
|
33
44
|
const names = [];
|
|
34
45
|
if (normalized !== SHARED_SKILL_NAME && available.includes(SHARED_SKILL_NAME)) {
|
|
@@ -37,12 +48,23 @@ export function resolvePackagedSkillNames(sourceRoot, requested = 'all') {
|
|
|
37
48
|
names.push(normalized);
|
|
38
49
|
return names;
|
|
39
50
|
}
|
|
51
|
+
function editDistance(left, right) {
|
|
52
|
+
let row = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
53
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
54
|
+
const next = [i + 1];
|
|
55
|
+
for (let j = 0; j < right.length; j += 1) {
|
|
56
|
+
next.push(Math.min(next[j] + 1, row[j + 1] + 1, row[j] + (left[i] === right[j] ? 0 : 1)));
|
|
57
|
+
}
|
|
58
|
+
row = next;
|
|
59
|
+
}
|
|
60
|
+
return row[right.length];
|
|
61
|
+
}
|
|
40
62
|
export function installPackagedSkills(sourceRoot, targetRoot, requested = 'all') {
|
|
41
63
|
const resolvedSourceRoot = resolve(sourceRoot);
|
|
42
64
|
const resolvedTargetRoot = resolve(targetRoot);
|
|
43
65
|
const skillNames = resolvePackagedSkillNames(resolvedSourceRoot, requested);
|
|
44
66
|
mkdirSync(resolvedTargetRoot, { recursive: true, mode: 0o700 });
|
|
45
|
-
const installed = skillNames.
|
|
67
|
+
const installed = skillNames.flatMap((name) => {
|
|
46
68
|
const source = resolveInside(resolvedSourceRoot, name);
|
|
47
69
|
const target = resolve(resolvedTargetRoot, basename(name));
|
|
48
70
|
statSync(resolve(source, 'SKILL.md'));
|
|
@@ -51,12 +73,28 @@ export function installPackagedSkills(sourceRoot, targetRoot, requested = 'all')
|
|
|
51
73
|
force: true,
|
|
52
74
|
filter: (entry) => shouldCopy(entry, source),
|
|
53
75
|
});
|
|
54
|
-
|
|
76
|
+
const current = {
|
|
55
77
|
name,
|
|
56
78
|
source,
|
|
57
79
|
target,
|
|
58
80
|
files: countFiles(target),
|
|
59
81
|
};
|
|
82
|
+
if (name !== SHARED_SKILL_NAME)
|
|
83
|
+
return [current];
|
|
84
|
+
const legacyTarget = resolve(resolvedTargetRoot, LEGACY_SHARED_SKILL_NAME);
|
|
85
|
+
rmSync(legacyTarget, { recursive: true, force: true });
|
|
86
|
+
cpSync(source, legacyTarget, {
|
|
87
|
+
recursive: true,
|
|
88
|
+
force: true,
|
|
89
|
+
filter: (entry) => shouldCopy(entry, source),
|
|
90
|
+
});
|
|
91
|
+
rewriteSkillName(resolve(legacyTarget, 'SKILL.md'), LEGACY_SHARED_SKILL_NAME);
|
|
92
|
+
return [current, {
|
|
93
|
+
name: LEGACY_SHARED_SKILL_NAME,
|
|
94
|
+
source,
|
|
95
|
+
target: legacyTarget,
|
|
96
|
+
files: countFiles(legacyTarget),
|
|
97
|
+
}];
|
|
60
98
|
});
|
|
61
99
|
return {
|
|
62
100
|
sourceRoot: resolvedSourceRoot,
|
|
@@ -65,6 +103,10 @@ export function installPackagedSkills(sourceRoot, targetRoot, requested = 'all')
|
|
|
65
103
|
installed,
|
|
66
104
|
};
|
|
67
105
|
}
|
|
106
|
+
function rewriteSkillName(skillPath, name) {
|
|
107
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
108
|
+
writeFileSync(skillPath, content.replace(/^name:\s*weaver-e10-shared\s*$/mu, `name: ${name}`), 'utf8');
|
|
109
|
+
}
|
|
68
110
|
function shouldCopy(entry, sourceRoot) {
|
|
69
111
|
const relativePath = relative(sourceRoot, entry);
|
|
70
112
|
const name = basename(entry);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
const SKILL_PREFIX = 'weaver-e10-';
|
|
4
|
+
const LEGACY_SKILL_PREFIX = 'weaver-work-cli-';
|
|
3
5
|
export class SkillReader {
|
|
4
6
|
root;
|
|
5
7
|
constructor(root) {
|
|
@@ -66,6 +68,14 @@ export class SkillReader {
|
|
|
66
68
|
throw new Error(`unknown skill: ${name}`);
|
|
67
69
|
}
|
|
68
70
|
const skillRoot = this.resolveInside(this.root, name);
|
|
71
|
+
if (!existsDirectoryWithSkill(skillRoot)) {
|
|
72
|
+
const normalized = normalizeLegacySkillName(name);
|
|
73
|
+
if (normalized !== name) {
|
|
74
|
+
const normalizedRoot = this.resolveInside(this.root, normalized);
|
|
75
|
+
if (existsDirectoryWithSkill(normalizedRoot))
|
|
76
|
+
return normalizedRoot;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
69
79
|
const info = statSync(skillRoot);
|
|
70
80
|
if (!info.isDirectory())
|
|
71
81
|
throw new Error(`unknown skill: ${name}`);
|
|
@@ -85,6 +95,23 @@ export class SkillReader {
|
|
|
85
95
|
return target;
|
|
86
96
|
}
|
|
87
97
|
}
|
|
98
|
+
function normalizeLegacySkillName(name) {
|
|
99
|
+
return name.startsWith(LEGACY_SKILL_PREFIX)
|
|
100
|
+
? `${SKILL_PREFIX}${name.slice(LEGACY_SKILL_PREFIX.length)}`
|
|
101
|
+
: name;
|
|
102
|
+
}
|
|
103
|
+
function existsDirectoryWithSkill(skillRoot) {
|
|
104
|
+
try {
|
|
105
|
+
const info = statSync(skillRoot);
|
|
106
|
+
if (!info.isDirectory())
|
|
107
|
+
return false;
|
|
108
|
+
statSync(resolve(skillRoot, 'SKILL.md'));
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
88
115
|
export function splitTarget(target) {
|
|
89
116
|
const index = target.indexOf('/');
|
|
90
117
|
if (index === -1)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { archiveValidationError } from './errors.js';
|
|
7
|
+
function stateRoot(ctx) {
|
|
8
|
+
const configured = ctx?.config?.path();
|
|
9
|
+
if (configured)
|
|
10
|
+
return resolve(configured, '..');
|
|
11
|
+
return process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve(homedir(), '.weaver-work-cli');
|
|
12
|
+
}
|
|
13
|
+
async function loadKey(ctx) {
|
|
14
|
+
const keysDir = resolve(stateRoot(ctx), 'keys');
|
|
15
|
+
const filename = resolve(keysDir, 'archive-continuation.key');
|
|
16
|
+
await mkdir(keysDir, { recursive: true, mode: 0o700 });
|
|
17
|
+
if (existsSync(filename))
|
|
18
|
+
return readFile(filename);
|
|
19
|
+
const key = randomBytes(32);
|
|
20
|
+
try {
|
|
21
|
+
await writeFile(filename, key, { flag: 'wx', mode: 0o600 });
|
|
22
|
+
if (process.platform !== 'win32')
|
|
23
|
+
await chmod(filename, 0o600).catch(() => undefined);
|
|
24
|
+
return key;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return readFile(filename);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function encode(value) {
|
|
31
|
+
return Buffer.from(JSON.stringify(value)).toString('base64url');
|
|
32
|
+
}
|
|
33
|
+
function signature(payload, key) {
|
|
34
|
+
return createHmac('sha256', key).update(payload).digest('base64url');
|
|
35
|
+
}
|
|
36
|
+
export function createArchiveContinuationSigner(ctx) {
|
|
37
|
+
return {
|
|
38
|
+
async issue(payload, ttlMs = 10 * 60_000) {
|
|
39
|
+
const issuedAt = Date.now();
|
|
40
|
+
const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
|
|
41
|
+
const sig = signature(body, await loadKey(ctx));
|
|
42
|
+
return `${body}.${sig}`;
|
|
43
|
+
},
|
|
44
|
+
async verify(token, expectedOperation) {
|
|
45
|
+
if (typeof token !== 'string' || !token.includes('.')) {
|
|
46
|
+
throw archiveValidationError('continuation_invalid', 'continuation 无效');
|
|
47
|
+
}
|
|
48
|
+
const [body, provided] = token.split('.');
|
|
49
|
+
const expected = signature(body, await loadKey(ctx));
|
|
50
|
+
const valid = provided.length === expected.length
|
|
51
|
+
&& timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
|
|
52
|
+
if (!valid)
|
|
53
|
+
throw archiveValidationError('continuation_invalid', 'continuation 签名校验失败');
|
|
54
|
+
let value;
|
|
55
|
+
try {
|
|
56
|
+
value = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw archiveValidationError('continuation_invalid', 'continuation 内容无法解析');
|
|
60
|
+
}
|
|
61
|
+
if (value.operation !== expectedOperation) {
|
|
62
|
+
throw archiveValidationError('continuation_mismatch', 'continuation 不属于当前操作');
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isSafeInteger(value.expiresAt) || value.expiresAt < Date.now()) {
|
|
65
|
+
throw archiveValidationError('continuation_expired', 'continuation 已过期');
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CliError, ExitCode } from '../../core/errors.js';
|
|
2
|
+
export class ArchiveCliError extends CliError {
|
|
3
|
+
type;
|
|
4
|
+
subtype;
|
|
5
|
+
code;
|
|
6
|
+
retryable;
|
|
7
|
+
stage;
|
|
8
|
+
details;
|
|
9
|
+
partialData;
|
|
10
|
+
constructor(type, subtype, message, options = {}) {
|
|
11
|
+
super(message, options.exitCode ?? ExitCode.InternalError);
|
|
12
|
+
this.name = 'ArchiveCliError';
|
|
13
|
+
this.type = type;
|
|
14
|
+
this.subtype = subtype;
|
|
15
|
+
this.code = options.code;
|
|
16
|
+
this.retryable = options.retryable ?? false;
|
|
17
|
+
this.stage = options.stage;
|
|
18
|
+
this.details = options.details;
|
|
19
|
+
this.partialData = options.partialData;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function archiveValidationError(subtype, message, details) {
|
|
23
|
+
return new ArchiveCliError('validation', subtype, message, {
|
|
24
|
+
details,
|
|
25
|
+
exitCode: ExitCode.UsageError,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function archiveAuthError(subtype, message, details) {
|
|
29
|
+
return new ArchiveCliError('authentication', subtype, message, {
|
|
30
|
+
details,
|
|
31
|
+
exitCode: ExitCode.AuthError,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function archiveNetworkError(subtype, message, options = {}) {
|
|
35
|
+
return new ArchiveCliError('network', subtype, message, {
|
|
36
|
+
...options,
|
|
37
|
+
retryable: options.retryable ?? true,
|
|
38
|
+
exitCode: ExitCode.NetworkError,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function archiveConfirmationError(action, details) {
|
|
42
|
+
return new ArchiveCliError('confirmation', 'required', '该操作需要明确确认', {
|
|
43
|
+
details: { action, ...details },
|
|
44
|
+
exitCode: ExitCode.ConfirmationRequired,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function archivePartialError(message, partialData, details) {
|
|
48
|
+
return new ArchiveCliError('partial', 'write_uncertain', message, {
|
|
49
|
+
details,
|
|
50
|
+
partialData,
|
|
51
|
+
exitCode: ExitCode.Partial,
|
|
52
|
+
});
|
|
53
|
+
}
|