@koishi-ce/plugin-market 1.0.13 → 1.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/dist/index.js +2 -2
- package/dist/style.css +1 -1
- package/lib/index.d.ts +14 -0
- package/lib/index.mjs +73 -2
- package/package.json +3 -1
- package/src/{__tests__/index.test.ts → index.test.ts} +105 -3
- package/src/node/installer.ts +106 -2
package/dist/style.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.confirm-panel td.arrow{padding:0}.confirm-panel td.arrow span{justify-content:center;align-items:center;display:flex}.confirm-panel .el-dialog__footer{justify-content:space-between;align-items:center;display:flex}.manual-panel .k-comment{margin-top:0}.dep-package-view[data-v-0fc4cb55]{height:3rem;position:relative}.dep-package-view .el-button[data-v-0fc4cb55]{width:4rem}.page-deps{flex-flow:column;display:flex}.page-deps .body-container{margin-top:-1px;transform:translateY(1px)}.page-deps table tr:first-child{border-top:none}.page-deps tbody tr{transition:all .3s}.page-deps tbody tr:hover{background-color:var(--k-side-bg)}@media (width<=768px){.page-deps td{padding:.5em}}.theme-color.primary{color:var(--primary)}.theme-color.success{color:var(--success)}.theme-color.warning{color:var(--warning)}.theme-color.danger{color:var(--danger)}.install-panel .el-dialog__header{align-items:center;gap:0 .5em;padding-bottom:4px;padding-right:36px;display:flex}.install-panel .el-dialog__header .el-dialog__title{color:var(--fg1);flex:none;margin-right:.5rem;font-weight:500}.install-panel .el-dialog__header .el-select{flex:auto;max-width:12.5rem;margin:-2px 0 -4px}.install-panel .warning{color:var(--k-color-warning)}.install-panel .danger{color:var(--k-color-danger)}.install-panel .version-badges{float:right;margin-right:-12px}.install-panel .el-dialog__body{min-height:40px;padding:0 20px}.install-panel .el-dialog__body>div{margin:1rem 0}.install-panel .el-dialog__body:last-child{padding-bottom:1rem}.install-panel table thead td,.install-panel table thead th,.install-panel table tbody td,.install-panel table tbody th{white-space:nowrap;padding:.5em .875em}.install-panel span.link:hover{cursor:pointer;text-decoration:underline}.install-panel .el-button+.el-button{margin-left:1rem}.install-panel .el-dialog__footer{justify-content:space-between;align-items:center;display:flex}.install-panel .wrapper{display:inline-flex;position:relative}.install-panel .wrapper .shadow{letter-spacing:1px;visibility:hidden;padding-right:22px}.install-panel .wrapper .el-select{position:absolute;top:50%;left:0;right:0;transform:translateY(-50%)}.dot-hint:before{content:"";background-color:currentColor;border-radius:100%;width:.5rem;height:.5rem;transition:background-color .3s;position:absolute;top:50%;right:20px;transform:translateY(-50%);box-shadow:1px 1px 2px #3333}.market-filter-item[data-v-6ec52c5f]{color:var(--k-text-normal);z-index:2;cursor:pointer;align-items:center;height:24px;margin:4px 0;transition:color .5s;display:flex}.market-filter-item[data-v-6ec52c5f]:hover{color:var(--k-text-dark)}.market-filter-item.active[data-v-6ec52c5f]{color:var(--k-text-active)}.market-filter-item.active.verified[data-v-6ec52c5f],.market-filter-item.active.newborn[data-v-6ec52c5f]{color:var(--k-color-success)}.market-filter-item.active.preview[data-v-6ec52c5f],.market-filter-item.active.portable[data-v-6ec52c5f]{color:var(--k-color-warning)}.market-filter-item.active.insecure[data-v-6ec52c5f]{color:var(--k-color-danger)}.market-filter-item.disabled[data-v-6ec52c5f]{opacity:.5;text-decoration:line-through;text-decoration-thickness:2px}.market-filter-item .icon[data-v-6ec52c5f]{justify-content:center;align-items:center;width:1.75rem;margin-right:4px;display:inline-flex}.market-filter-item:not(.active) .order[data-v-6ec52c5f]{display:none}.market-filter-item .order[data-v-6ec52c5f]{justify-content:center;align-items:center;width:1.75rem;display:inline-flex}.market-filter-item svg[data-v-6ec52c5f]{max-width:1.125rem;height:1rem}.market-filter-item .text[data-v-6ec52c5f],.market-filter-item .count[data-v-6ec52c5f]{font-size:14px;font-weight:500;line-height:20px}.market-filter-item .count[data-v-6ec52c5f]{margin-right:4px}.market-filter-item .spacer[data-v-6ec52c5f]{flex:1}.k-schema-item p{margin:.25rem;font-size:.875rem;line-height:1.7}.k-schema-item .markdown p{margin:0}.k-schema-item ul{width:100%;padding-left:1rem;font-size:.875rem;list-style:none}.k-schema-item ul .el-radio,.k-schema-item ul .el-checkbox{height:1.375rem}.k-schema-item .el-button+.el-button{margin-left:0}.k-schema-item .k-schema-main{grid-template-columns:1fr auto 2rem;justify-content:space-between;align-items:center;gap:.25rem 1rem;min-height:3rem;display:grid}.k-schema-item h3{-webkit-user-select:none;user-select:none;align-items:center;margin:0;font-size:1rem;line-height:1.7;display:flex;position:relative}.k-schema-item h3>*{flex:none}.k-schema-item h3 .prefix{text-overflow:ellipsis;flex:0 auto;font-weight:400;overflow:hidden}.k-schema-item .k-schema-right{flex:1;justify-content:flex-end;gap:1rem;display:flex}.k-schema-item .el-button.ellipsis{padding:8px 9px}.k-schema-item .el-button.ellipsis .k-icon{width:12px}.k-schema-item .bottom{margin:.5rem 0 .25rem}.k-schema-item .actions{width:.5rem;height:100%;transition:var(--color-transition);border-left:2px solid #0000;position:absolute;top:0;left:0}.k-schema-item.changed .actions{border-left-color:var(--el-color-primary)}.k-schema-item.required .actions{border-left-color:var(--el-color-error)}.k-schema-item.invalid .actions{border-left-color:var(--el-color-warning)}.k-schema-item .el-input .suffix-icon{justify-content:center;align-items:center;width:1rem;margin-left:6px;display:flex}.k-schema-item .el-input .k-icon{color:var(--k-text-light);transition:var(--color-transition);cursor:pointer;height:.75rem}.k-schema-item .el-input .k-icon:hover{color:var(--k-text-dark)}.k-schema-item .el-input .k-icon.invalid{cursor:auto;color:var(--k-color-danger)}.k-schema-item .el-input.nullable:not(:focus-within) .el-input__prefix{border-top:var(--el-border);width:40%;transition:var(--color-transition);display:block;position:absolute;top:50%}.k-schema-item .el-input .el-input__wrapper{padding-right:9px}.k-schema-item .el-input:not(.minimal).invalid .el-input__wrapper:hover,.k-schema-item .el-input:not(.minimal).invalid .el-input__wrapper.is-focus{box-shadow:0 0 0 1px var(--k-color-danger) inset}.k-schema-item .el-input-number .el-input__wrapper{padding-right:42px}.k-schema-item .el-switch.nullable .el-switch__core{border:1px solid var(--el-border-color);background-color:#0000}.k-schema-item .el-switch.nullable .el-switch__action{background-color:var(--el-border-color);border-radius:0;width:16px;height:1px;left:11px}.k-schema-item .el-switch.nullable:hover .el-switch__core{border-color:var(--el-color-primary)}.entry-input[data-v-e26e0849]{position:relative}.entry-input .shadow[data-v-e26e0849]{visibility:hidden;white-space:pre}.entry-input .placeholder[data-v-e26e0849]{min-width:2rem;display:inline-block}.entry-input input[data-v-e26e0849]{font-size:1em;font-weight:inherit;border:none;border-radius:0;outline:none;margin:0;padding:0 .5em;font-family:inherit;position:absolute;left:-.5em;right:-.5em}.k-schema-table-container{position:relative}.k-schema-table-container .cell-outline{box-sizing:border-box;border:1px solid var(--k-color-active);pointer-events:none;position:absolute}.k-schema-table-container .cell-outline.invalid{border-color:var(--k-color-danger)}.k-schema-table td,.k-schema-table th{border:1px solid var(--el-border-color)}.k-schema-table th{padding:.5rem .75rem;line-height:1.25rem}.k-schema-table td{transition:var(--color-transition);padding:0}.k-schema-table td:hover{background-color:var(--k-button-hover-bg)}.k-schema-table td.k-schema-table-button{width:2rem;max-width:2rem;color:var(--k-text-light);cursor:pointer}.k-schema-table td.k-schema-table-button:hover{color:var(--k-color-active)}.k-schema-table td.k-schema-table-button .inner{box-sizing:border-box;justify-content:center;align-items:center;height:2rem;display:flex}.k-schema-table td.k-schema-table-button .k-icon{height:1rem}.k-schema-table td.k-schema-table-button.disabled{color:var(--k-color-disabled);pointer-events:none}.k-badge{color:#fff;white-space:nowrap;vertical-align:baseline;border-radius:4px;height:1.25rem;margin-left:.5rem;padding:0 6px;font-size:14px;font-weight:500;line-height:1.25rem;display:inline-block}.k-badge.primary{background-color:var(--k-color-primary)}.k-badge.warning{background-color:var(--k-color-warning)}.k-badge.success{background-color:var(--k-color-success)}.k-badge.danger{background-color:var(--k-color-danger)}.k-form:not(:first-child){margin-top:2rem}@media screen and (width<=480px){.k-form{margin:0 -1.5rem}.k-form .k-schema-header{padding:0 1.5rem}.k-form .k-schema-item{padding:.5rem 1.5rem}.k-form .k-schema-item .k-schema-main{min-height:unset;grid-template-rows:auto auto;grid-template-columns:auto 2rem}.k-form .k-schema-item .k-schema-right{grid-area:2/1/auto/2;display:block}.k-form .k-schema-item .k-schema-right>:first-child{margin-top:.25rem}.k-form .k-schema-item .k-schema-right>:last-child{margin-bottom:.25rem}}.k-menu,.k-menu.el-popper.is-light{z-index:1000;background-color:var(--el-bg-color-overlay);min-width:12rem;box-shadow:var(--k-menu-shadow);border-radius:6px;padding:.375rem 0;font-size:14px;position:fixed}.k-menu-separator{border-top:1px solid var(--el-border-color-light);margin:.375rem 0}.k-menu-separator:first-child,.k-menu-separator:last-child,.k-menu-separator+.k-menu-separator{display:none}.k-menu-item{-webkit-user-select:none;user-select:none;cursor:pointer;transition:var(--color-transition);border-radius:4px;margin:0 .375rem;padding:.375rem 0 .375rem 2.5rem;position:relative}.k-menu-item.disabled{color:var(--k-color-disabled);pointer-events:none}.k-menu-item:not(.disabled):hover{background-color:var(--k-hover-bg);color:inherit!important}.k-menu-item:not(.disabled).primary{color:var(--el-color-primary)}.k-menu-item:not(.disabled).primary:hover{background-color:var(--el-color-primary)}.k-menu-item:not(.disabled).danger{color:var(--el-color-error)}.k-menu-item:not(.disabled).danger:hover{background-color:var(--el-color-error)}.k-menu-item:not(.disabled).warning{color:var(--el-color-warning)}.k-menu-item:not(.disabled).warning:hover{background-color:var(--el-color-warning)}.k-menu-icon{justify-content:center;align-items:center;width:2.5rem;height:100%;display:flex;position:absolute;top:0;left:0}.k-menu-icon .k-icon{height:1rem}.k-schema-item{border-bottom:1px solid var(--el-border-color-light);transition:var(--color-transition);padding:.5rem 1rem;position:relative}.k-schema-item:first-child,:not(.k-schema-item):not(.k-schema-group)+.k-schema-item{border-top:1px solid var(--el-border-color-light)}.k-schema-item+h2{margin-top:2rem}.k-schema-item:hover{background-color:var(--el-fill-color)}.k-schema-item .k-schema-right .el-select{width:12rem}.k-schema-header{margin:1rem 0;font-size:1.25rem}.k-schema-header:not(:first-child){margin-top:2rem}.k-schema-group{position:relative}.k-schema-group:empty{border-bottom:none}.k-schema-group>:first-child{border-top:none}.k-schema-table .el-input,.k-schema-table .el-input-number{width:100%}.k-schema-table-cell-input,.k-schema-table-cell-input-number,.k-schema-table-cell-select{min-width:6rem}.k-schema-table .el-input__wrapper,.k-schema-table .el-select__wrapper{box-shadow:none!important}.el-input.invalid .el-input__wrapper,.el-textarea.invalid .el-textarea__inner{box-shadow:0 0 0 1px var(--el-color-danger) inset}.k-schema-edit-dialog .el-dialog__footer{justify-content:space-between;display:flex}.k-filter-expr{flex:1 0 auto;display:inline-flex}.k-filter-expr .entity,.k-filter-expr .operator{flex:none;width:7.5rem}.k-filter-expr .value{flex:1 0 auto;width:auto}.k-filter-item{display:flex}.overlay-enter-from,.overlay-leave-to{opacity:0}.overlay-enter,.overlay-leave{opacity:1}.image-viewer{position:absolute;inset:0}.image-viewer .button{cursor:pointer;-webkit-user-select:none;user-select:none;opacity:.5;background-color:#303133;border-radius:3rem;justify-content:space-evenly;align-items:center;height:3rem;font-size:1.5rem;transition:all .4s;display:flex;position:absolute}.image-viewer .button .k-icon{height:1.25rem;transition:all .4s}.image-viewer .button:not(.disabled):hover{opacity:.8}.image-viewer .button:not(.disabled) .k-icon:hover{color:#f4f4f5cc}.image-viewer .button.left{z-index:2000;width:3rem;top:50%;left:3rem;transform:translateY(-50%)}.image-viewer .button.left .k-icon{margin-left:-3px}.image-viewer .button.right{z-index:2000;width:3rem;top:50%;right:3rem;transform:translateY(-50%)}.image-viewer .button.right .k-icon{margin-right:-3px}.image-viewer .button.bottom{z-index:2000;width:18rem;bottom:3rem;left:50%;transform:translate(-50%)}.image-viewer .button.disabled{cursor:not-allowed}.image-viewer img{transition:all .3s;position:absolute}.k-link{cursor:pointer;text-decoration:underline}.k-link:hover{text-decoration:underline}.cursor-pointer[data-v-c57f6ae3]{cursor:pointer}.market-package[data-v-c57f6ae3]{box-sizing:border-box;width:100%;max-width:540px;height:calc(12.5rem + 2px);margin:0;padding:1rem 1.25rem;transition:box-shadow .3s;box-shadow:inset 0 0 0 2px #0000}.market-package[data-v-c57f6ae3]:hover{box-shadow:0 0 0 2px inset var(--k-color-primary)}.market-package .market-icon[data-v-c57f6ae3]{height:1em;display:inline}.market-package .header[data-v-c57f6ae3],.market-package .footer[data-v-c57f6ae3]{flex:none}.market-package .header[data-v-c57f6ae3]{position:relative}.market-package .header .left[data-v-c57f6ae3]{border:1px solid var(--k-color-border);box-sizing:border-box;border-radius:8px;width:3.5rem;height:3.5rem}.market-package .header .left svg[data-v-c57f6ae3]{height:1.75rem}.market-package .header h2[data-v-c57f6ae3]{align-items:center;margin:0;font-size:1.125rem;line-height:1;display:flex}.market-package .header h2 .title[data-v-c57f6ae3]{flex:0 auto;line-height:1.5rem;display:inline-block}.market-package .header h2 .icon[data-v-c57f6ae3]{vertical-align:-2px;cursor:pointer;width:1.125rem;height:1.125rem;margin-left:.6rem;display:inline-block;position:relative}.market-package .header h2 .icon .market-icon[data-v-c57f6ae3]{z-index:10;height:100%;transition:color .3s;position:relative}.market-package .header h2 .icon.verified[data-v-c57f6ae3],.market-package .header h2 .icon.newborn[data-v-c57f6ae3]{color:var(--k-color-success)}.market-package .header h2 .icon.preview[data-v-c57f6ae3]{color:var(--k-color-warning)}.market-package .header h2 .icon.insecure[data-v-c57f6ae3]{color:var(--k-color-danger)}.market-package .header h2 .icon.verified[data-v-c57f6ae3]:before,.market-package .header h2 .icon.insecure[data-v-c57f6ae3]:before{content:"";z-index:0;background-color:#fff;border-radius:100%;position:absolute;inset:25%}.market-package .header .rating[data-v-c57f6ae3]{align-items:center;gap:0 .25rem;width:fit-content;height:1.5rem;display:inline-flex}.market-package .header .rating .market-icon[data-v-c57f6ae3]{color:var(--k-color-warning);height:.875rem;transition:color .3s}.market-package .desc[data-v-c57f6ae3]{word-break:break-word;text-overflow:ellipsis;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:auto;margin:0;font-size:15px;line-height:1.5;display:-webkit-box;overflow:hidden}.market-package .footer[data-v-c57f6ae3]{cursor:default;align-items:center;gap:.5rem;height:1.5rem;margin-bottom:-.25rem;font-size:14px;transition:color .3s;display:flex;overflow:hidden}.market-package .footer[data-v-c57f6ae3]>*{flex:none}.market-package .footer .spacer[data-v-c57f6ae3]{flex:0 2 .5rem}.market-package .footer .long-spacer[data-v-c57f6ae3]{flex:auto}.market-package .footer .market-icon[data-v-c57f6ae3]{vertical-align:-1px;width:16px;height:12px;margin-right:6px}.market-package .footer .avatars[data-v-c57f6ae3]{gap:.25rem;display:flex}.market-package .footer .avatars .avatar[data-v-c57f6ae3]{cursor:pointer}.market-package .footer .avatars img[data-v-c57f6ae3]{vertical-align:middle;border-radius:100%;width:1.5rem;height:1.5rem}.package-list[data-v-a0cd1fb0]{gap:var(--card-margin);flex:1 0 auto;grid-template-columns:repeat(auto-fill,minmax(336px,1fr));justify-items:center;display:grid}.pagination[data-v-a0cd1fb0]{margin:var(--card-margin) 0;justify-content:center}.k-empty[data-v-a0cd1fb0]{flex:1 0 auto}.search-box[data-v-ddf3d744]{border-radius:1.5rem;align-items:center;width:100%;max-width:600px;margin:2rem auto 0;display:flex}.search-container[data-v-ddf3d744]{flex-wrap:wrap;flex:auto;align-items:center;gap:8px 6px;padding:.75rem 0 .75rem 1.25rem;display:flex}.search-container input[data-v-ddf3d744]{box-sizing:border-box;min-width:10rem;height:1.25rem;color:inherit;background-color:#0000;border:none;outline:none;flex:auto;padding:0;font-size:.9em}.search-action[data-v-ddf3d744]{cursor:pointer;flex-direction:column;flex:none;justify-content:center;align-items:center;width:3rem;height:2.5rem;display:flex}.search-action .market-icon[data-v-ddf3d744]{opacity:.5;height:1rem}.search-action:hover .market-icon.search[data-v-ddf3d744],.search-action:not(:hover) .market-icon.close[data-v-ddf3d744]{display:none}.search-word[data-v-ddf3d744]{box-sizing:border-box;color:#fff;white-space:nowrap;vertical-align:baseline;background-color:var(--k-fill-normal);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:4px;flex:none;height:1.25rem;padding:2px 6px;font-size:14px;font-weight:500;line-height:1rem;transition:opacity .3s,background-color .3s;display:inline-block}.search-word.invalid[data-v-ddf3d744]{opacity:.5;text-decoration:line-through}.search-word.invalid[data-v-ddf3d744]:hover{opacity:1}.page-market .layout-main .el-scrollbar__view{padding:0 var(--card-margin);flex-direction:column;min-height:100%;display:flex}.page-market .layout-left .market-filter-group{margin:2rem 0;padding:0 1.5rem}.page-market .layout-left h2{margin:0;padding:8px 0;font-size:14px}.search-box{background-color:var(--k-card-bg);box-shadow:var(--k-card-shadow);transition:var(--color-transition)}.market-hint{width:100%;color:var(--el-text-color-regular);font-size:var(--el-font-size-base);font-weight:var(--el-font-weight-primary);margin:1rem 0 -.5rem;transition:color .3s}.market-hint .el-checkbox{margin-left:1.5rem}.market-container .k-button{margin-left:1rem;padding:.35em .85em;transform:translateY(-1px)}.market-error.k-comment{margin-left:2rem;margin-right:2rem}.k-status .el-progress-bar{width:120px;margin-right:2px}.dialog-config-fork .el-dialog__header .el-dialog__title{color:var(--fg1);flex:none;margin-right:.5rem;font-weight:500}.dialog-config-fork .status-light{margin-right:.75rem}.dialog-config-fork .actions{justify-content:flex-end;align-items:center;gap:0 .5rem;display:flex}.dialog-config-fork .action{cursor:pointer;width:1.25rem;color:var(--fg2);transition:var(--color-transition);justify-content:center;display:inline-flex}.dialog-config-fork .action:hover{color:var(--fg1)}.dialog-config-fork .el-dialog__footer{justify-content:space-between;align-items:center;font-size:.9em;display:flex}.modifier,.plugin-view .markdown.usage{margin-bottom:2rem}.plugin-view .markdown.usage h2{font-size:1.25rem}.plugin-tree{width:100%;height:100%;overflow:auto}.plugin-tree .el-scrollbar__view{padding:1rem 0;line-height:2.25rem}.plugin-tree .search{padding:0 1.5rem}.plugin-tree .k-icon-filter{height:15px}.plugin-tree .el-tree-node.is-group>.el-tree-node__content{font-weight:700}.plugin-tree .el-tree-node__content .item{flex:1;justify-content:space-between;align-items:center;height:100%;display:flex;overflow:hidden}.plugin-tree .el-tree-node__content .label{text-overflow:ellipsis;transition:var(--color-transition);overflow:hidden}.plugin-tree .el-tree-node__content .right{height:100%;margin:0 1.5rem 0 .5rem}.end{margin-right:.5rem}.config-header{margin:0 0 2rem;font-size:1.375rem;line-height:2rem}.config-header .k-button{float:right}.plugin-view .k-content>:first-child{margin-top:0}.plugin-select .el-dialog__header{border-bottom:1px solid var(--k-color-divider);justify-content:space-between;align-items:center;margin-right:0;padding:12px 20px;display:flex}.plugin-select .el-dialog__header button{top:2px}.plugin-select .el-dialog__header .title{flex:none}.plugin-select .el-dialog__header .el-input{width:220px;height:2rem;display:inline-block}.plugin-select .el-dialog__body{height:50vh;padding:0;display:flex}.plugin-select .el-dialog__body .tabs{border-right:1px solid var(--k-color-divider);flex:none;width:7.5rem;font-size:15px}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs{width:3rem}}.plugin-select .el-dialog__body .tabs .el-scrollbar__view{padding:.5rem 0}.plugin-select .el-dialog__body .tabs .tab-item{cursor:pointer;height:2rem;transition:var(--color-transition);justify-content:center;align-items:center;padding:0 1rem;font-size:.875rem;display:flex}.plugin-select .el-dialog__body .tabs .tab-item:hover{background-color:var(--k-hover-bg)}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs .tab-item{padding:0}}.plugin-select .el-dialog__body .tabs .tab-item .market-icon{width:1.25rem;height:1rem}.plugin-select .el-dialog__body .tabs .tab-item.active{color:var(--primary)}.plugin-select .el-dialog__body .tabs .tab-item .title{width:3.5rem;margin-left:.5rem}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs .tab-item .title{display:none}}.plugin-select .el-dialog__body .content{flex:auto}.plugin-select .el-dialog__body .content .package{cursor:pointer;transition:var(--color-transition);padding:.5rem 1rem}.plugin-select .el-dialog__body .content .package h3{margin:0 0 .25rem;font-size:16px}.plugin-select .el-dialog__body .content .package p{margin:0;font-size:14px}.plugin-select .el-dialog__body .content .package:hover{background-color:var(--k-hover-bg)}.absolute{position:absolute}.relative{position:relative}.grid{display:grid}.my-8{margin-top:2rem;margin-bottom:2rem}.inline{display:inline}.block{display:block}.inline-block{display:inline-block}.hidden{display:none}.h2{height:.5rem}.h3{height:.75rem}.flex{display:flex}.inline-flex{display:inline-flex}.shrink-0{flex-shrink:0}.grow-1{flex-grow:1}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-4{column-gap:1rem}.gap-y-2{row-gap:.5rem}.overflow-hidden{overflow:hidden}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.b,.border{border-width:1px}.px{padding-left:1rem;padding-right:1rem}.pl-8{padding-left:2rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.shadow{--un-shadow:var(--un-shadow-inset) 0 1px 3px 0 var(--un-shadow-color,#0000001a),var(--un-shadow-inset) 0 1px 2px -1px var(--un-shadow-color,#0000001a);box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow)}.outline{outline-style:solid}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease{transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog-config-fork .status-light,.plugin-tree .status-light{width:.625rem;height:.625rem;transition:var(--color-transition);border-radius:100%;display:inline-block}.dialog-config-fork .status-light.active,.plugin-tree .status-light.active{background-color:var(--k-color-success)}.dialog-config-fork .status-light.pending,.plugin-tree .status-light.pending{background-color:var(--k-color-warning)}.dialog-config-fork .status-light.loading,.plugin-tree .status-light.loading{background-color:var(--k-color-warning);animation:1s infinite status-flash}.dialog-config-fork .status-light.failed,.plugin-tree .status-light.failed{background-color:var(--k-color-danger)}.dialog-config-fork .status-light.disabled:not(.ignore-disabled),.plugin-tree .status-light.disabled:not(.ignore-disabled){opacity:.5;background-color:var(--k-color-disabled)}@keyframes status-flash{0%,to{opacity:0}50%{opacity:1}}
|
|
1
|
+
.confirm-panel td.arrow{padding:0}.confirm-panel td.arrow span{justify-content:center;align-items:center;display:flex}.confirm-panel .el-dialog__footer{justify-content:space-between;align-items:center;display:flex}.manual-panel .k-comment{margin-top:0}.dep-package-view[data-v-0fc4cb55]{height:3rem;position:relative}.dep-package-view .el-button[data-v-0fc4cb55]{width:4rem}.page-deps{flex-flow:column;display:flex}.page-deps .body-container{margin-top:-1px;transform:translateY(1px)}.page-deps table tr:first-child{border-top:none}.page-deps tbody tr{transition:all .3s}.page-deps tbody tr:hover{background-color:var(--k-side-bg)}@media (width<=768px){.page-deps td{padding:.5em}}.theme-color.primary{color:var(--primary)}.theme-color.success{color:var(--success)}.theme-color.warning{color:var(--warning)}.theme-color.danger{color:var(--danger)}.install-panel .el-dialog__header{align-items:center;gap:0 .5em;padding-bottom:4px;padding-right:36px;display:flex}.install-panel .el-dialog__header .el-dialog__title{color:var(--fg1);flex:none;margin-right:.5rem;font-weight:500}.install-panel .el-dialog__header .el-select{flex:auto;max-width:12.5rem;margin:-2px 0 -4px}.install-panel .warning{color:var(--k-color-warning)}.install-panel .danger{color:var(--k-color-danger)}.install-panel .version-badges{float:right;margin-right:-12px}.install-panel .el-dialog__body{min-height:40px;padding:0 20px}.install-panel .el-dialog__body>div{margin:1rem 0}.install-panel .el-dialog__body:last-child{padding-bottom:1rem}.install-panel table thead td,.install-panel table thead th,.install-panel table tbody td,.install-panel table tbody th{white-space:nowrap;padding:.5em .875em}.install-panel span.link:hover{cursor:pointer;text-decoration:underline}.install-panel .el-button+.el-button{margin-left:1rem}.install-panel .el-dialog__footer{justify-content:space-between;align-items:center;display:flex}.install-panel .wrapper{display:inline-flex;position:relative}.install-panel .wrapper .shadow{letter-spacing:1px;visibility:hidden;padding-right:22px}.install-panel .wrapper .el-select{position:absolute;top:50%;left:0;right:0;transform:translateY(-50%)}.dot-hint:before{content:"";background-color:currentColor;border-radius:100%;width:.5rem;height:.5rem;transition:background-color .3s;position:absolute;top:50%;right:20px;transform:translateY(-50%);box-shadow:1px 1px 2px #3333}.k-schema-item p{margin:.25rem;font-size:.875rem;line-height:1.7}.k-schema-item .markdown p{margin:0}.k-schema-item ul{width:100%;padding-left:1rem;font-size:.875rem;list-style:none}.k-schema-item ul .el-radio,.k-schema-item ul .el-checkbox{height:1.375rem}.k-schema-item .el-button+.el-button{margin-left:0}.k-schema-item .k-schema-main{grid-template-columns:1fr auto 2rem;justify-content:space-between;align-items:center;gap:.25rem 1rem;min-height:3rem;display:grid}.k-schema-item h3{-webkit-user-select:none;user-select:none;align-items:center;margin:0;font-size:1rem;line-height:1.7;display:flex;position:relative}.k-schema-item h3>*{flex:none}.k-schema-item h3 .prefix{text-overflow:ellipsis;flex:0 auto;font-weight:400;overflow:hidden}.k-schema-item .k-schema-right{flex:1;justify-content:flex-end;gap:1rem;display:flex}.k-schema-item .el-button.ellipsis{padding:8px 9px}.k-schema-item .el-button.ellipsis .k-icon{width:12px}.k-schema-item .bottom{margin:.5rem 0 .25rem}.k-schema-item .actions{width:.5rem;height:100%;transition:var(--color-transition);border-left:2px solid #0000;position:absolute;top:0;left:0}.k-schema-item.changed .actions{border-left-color:var(--el-color-primary)}.k-schema-item.required .actions{border-left-color:var(--el-color-error)}.k-schema-item.invalid .actions{border-left-color:var(--el-color-warning)}.k-schema-item .el-input .suffix-icon{justify-content:center;align-items:center;width:1rem;margin-left:6px;display:flex}.k-schema-item .el-input .k-icon{color:var(--k-text-light);transition:var(--color-transition);cursor:pointer;height:.75rem}.k-schema-item .el-input .k-icon:hover{color:var(--k-text-dark)}.k-schema-item .el-input .k-icon.invalid{cursor:auto;color:var(--k-color-danger)}.k-schema-item .el-input.nullable:not(:focus-within) .el-input__prefix{border-top:var(--el-border);width:40%;transition:var(--color-transition);display:block;position:absolute;top:50%}.k-schema-item .el-input .el-input__wrapper{padding-right:9px}.k-schema-item .el-input:not(.minimal).invalid .el-input__wrapper:hover,.k-schema-item .el-input:not(.minimal).invalid .el-input__wrapper.is-focus{box-shadow:0 0 0 1px var(--k-color-danger) inset}.k-schema-item .el-input-number .el-input__wrapper{padding-right:42px}.k-schema-item .el-switch.nullable .el-switch__core{border:1px solid var(--el-border-color);background-color:#0000}.k-schema-item .el-switch.nullable .el-switch__action{background-color:var(--el-border-color);border-radius:0;width:16px;height:1px;left:11px}.k-schema-item .el-switch.nullable:hover .el-switch__core{border-color:var(--el-color-primary)}.entry-input[data-v-e26e0849]{position:relative}.entry-input .shadow[data-v-e26e0849]{visibility:hidden;white-space:pre}.entry-input .placeholder[data-v-e26e0849]{min-width:2rem;display:inline-block}.entry-input input[data-v-e26e0849]{font-size:1em;font-weight:inherit;border:none;border-radius:0;outline:none;margin:0;padding:0 .5em;font-family:inherit;position:absolute;left:-.5em;right:-.5em}.k-schema-table-container{position:relative}.k-schema-table-container .cell-outline{box-sizing:border-box;border:1px solid var(--k-color-active);pointer-events:none;position:absolute}.k-schema-table-container .cell-outline.invalid{border-color:var(--k-color-danger)}.k-schema-table td,.k-schema-table th{border:1px solid var(--el-border-color)}.k-schema-table th{padding:.5rem .75rem;line-height:1.25rem}.k-schema-table td{transition:var(--color-transition);padding:0}.k-schema-table td:hover{background-color:var(--k-button-hover-bg)}.k-schema-table td.k-schema-table-button{width:2rem;max-width:2rem;color:var(--k-text-light);cursor:pointer}.k-schema-table td.k-schema-table-button:hover{color:var(--k-color-active)}.k-schema-table td.k-schema-table-button .inner{box-sizing:border-box;justify-content:center;align-items:center;height:2rem;display:flex}.k-schema-table td.k-schema-table-button .k-icon{height:1rem}.k-schema-table td.k-schema-table-button.disabled{color:var(--k-color-disabled);pointer-events:none}.k-badge{color:#fff;white-space:nowrap;vertical-align:baseline;border-radius:4px;height:1.25rem;margin-left:.5rem;padding:0 6px;font-size:14px;font-weight:500;line-height:1.25rem;display:inline-block}.k-badge.primary{background-color:var(--k-color-primary)}.k-badge.warning{background-color:var(--k-color-warning)}.k-badge.success{background-color:var(--k-color-success)}.k-badge.danger{background-color:var(--k-color-danger)}.k-form:not(:first-child){margin-top:2rem}@media screen and (width<=480px){.k-form{margin:0 -1.5rem}.k-form .k-schema-header{padding:0 1.5rem}.k-form .k-schema-item{padding:.5rem 1.5rem}.k-form .k-schema-item .k-schema-main{min-height:unset;grid-template-rows:auto auto;grid-template-columns:auto 2rem}.k-form .k-schema-item .k-schema-right{grid-area:2/1/auto/2;display:block}.k-form .k-schema-item .k-schema-right>:first-child{margin-top:.25rem}.k-form .k-schema-item .k-schema-right>:last-child{margin-bottom:.25rem}}.k-menu,.k-menu.el-popper.is-light{z-index:1000;background-color:var(--el-bg-color-overlay);min-width:12rem;box-shadow:var(--k-menu-shadow);border-radius:6px;padding:.375rem 0;font-size:14px;position:fixed}.k-menu-separator{border-top:1px solid var(--el-border-color-light);margin:.375rem 0}.k-menu-separator:first-child,.k-menu-separator:last-child,.k-menu-separator+.k-menu-separator{display:none}.k-menu-item{-webkit-user-select:none;user-select:none;cursor:pointer;transition:var(--color-transition);border-radius:4px;margin:0 .375rem;padding:.375rem 0 .375rem 2.5rem;position:relative}.k-menu-item.disabled{color:var(--k-color-disabled);pointer-events:none}.k-menu-item:not(.disabled):hover{background-color:var(--k-hover-bg);color:inherit!important}.k-menu-item:not(.disabled).primary{color:var(--el-color-primary)}.k-menu-item:not(.disabled).primary:hover{background-color:var(--el-color-primary)}.k-menu-item:not(.disabled).danger{color:var(--el-color-error)}.k-menu-item:not(.disabled).danger:hover{background-color:var(--el-color-error)}.k-menu-item:not(.disabled).warning{color:var(--el-color-warning)}.k-menu-item:not(.disabled).warning:hover{background-color:var(--el-color-warning)}.k-menu-icon{justify-content:center;align-items:center;width:2.5rem;height:100%;display:flex;position:absolute;top:0;left:0}.k-menu-icon .k-icon{height:1rem}.k-schema-item{border-bottom:1px solid var(--el-border-color-light);transition:var(--color-transition);padding:.5rem 1rem;position:relative}.k-schema-item:first-child,:not(.k-schema-item):not(.k-schema-group)+.k-schema-item{border-top:1px solid var(--el-border-color-light)}.k-schema-item+h2{margin-top:2rem}.k-schema-item:hover{background-color:var(--el-fill-color)}.k-schema-item .k-schema-right .el-select{width:12rem}.k-schema-header{margin:1rem 0;font-size:1.25rem}.k-schema-header:not(:first-child){margin-top:2rem}.k-schema-group{position:relative}.k-schema-group:empty{border-bottom:none}.k-schema-group>:first-child{border-top:none}.k-schema-table .el-input,.k-schema-table .el-input-number{width:100%}.k-schema-table-cell-input,.k-schema-table-cell-input-number,.k-schema-table-cell-select{min-width:6rem}.k-schema-table .el-input__wrapper,.k-schema-table .el-select__wrapper{box-shadow:none!important}.el-input.invalid .el-input__wrapper,.el-textarea.invalid .el-textarea__inner{box-shadow:0 0 0 1px var(--el-color-danger) inset}.k-schema-edit-dialog .el-dialog__footer{justify-content:space-between;display:flex}.k-filter-expr{flex:1 0 auto;display:inline-flex}.k-filter-expr .entity,.k-filter-expr .operator{flex:none;width:7.5rem}.k-filter-expr .value{flex:1 0 auto;width:auto}.k-filter-item{display:flex}.overlay-enter-from,.overlay-leave-to{opacity:0}.overlay-enter,.overlay-leave{opacity:1}.image-viewer{position:absolute;inset:0}.image-viewer .button{cursor:pointer;-webkit-user-select:none;user-select:none;opacity:.5;background-color:#303133;border-radius:3rem;justify-content:space-evenly;align-items:center;height:3rem;font-size:1.5rem;transition:all .4s;display:flex;position:absolute}.image-viewer .button .k-icon{height:1.25rem;transition:all .4s}.image-viewer .button:not(.disabled):hover{opacity:.8}.image-viewer .button:not(.disabled) .k-icon:hover{color:#f4f4f5cc}.image-viewer .button.left{z-index:2000;width:3rem;top:50%;left:3rem;transform:translateY(-50%)}.image-viewer .button.left .k-icon{margin-left:-3px}.image-viewer .button.right{z-index:2000;width:3rem;top:50%;right:3rem;transform:translateY(-50%)}.image-viewer .button.right .k-icon{margin-right:-3px}.image-viewer .button.bottom{z-index:2000;width:18rem;bottom:3rem;left:50%;transform:translate(-50%)}.image-viewer .button.disabled{cursor:not-allowed}.image-viewer img{transition:all .3s;position:absolute}.k-link{cursor:pointer;text-decoration:underline}.k-link:hover{text-decoration:underline}.market-filter-item[data-v-542fc917]{box-sizing:border-box;color:var(--k-text-normal);z-index:2;cursor:pointer;border-radius:8px;align-items:center;height:28px;margin:2px 0;padding:0 .5rem;transition:color .2s,background-color .2s;display:flex}.market-filter-item[data-v-542fc917]:hover{color:var(--k-text-dark);background-color:var(--k-hover-bg)}.market-filter-item.active[data-v-542fc917]{color:var(--k-color-primary);background-color:color-mix(in srgb, var(--k-color-primary) 10%, transparent)}.market-filter-item.active .text[data-v-542fc917]{font-weight:600}.market-filter-item.active.verified[data-v-542fc917],.market-filter-item.active.newborn[data-v-542fc917]{color:var(--k-color-success);background-color:color-mix(in srgb, var(--k-color-success) 10%, transparent)}.market-filter-item.active.preview[data-v-542fc917],.market-filter-item.active.portable[data-v-542fc917]{color:var(--k-color-warning);background-color:color-mix(in srgb, var(--k-color-warning) 10%, transparent)}.market-filter-item.active.insecure[data-v-542fc917]{color:var(--k-color-danger);background-color:color-mix(in srgb, var(--k-color-danger) 10%, transparent)}.market-filter-item.disabled[data-v-542fc917]{opacity:.5;text-decoration:line-through;text-decoration-thickness:2px}.market-filter-item .icon[data-v-542fc917]{justify-content:center;align-items:center;width:1.75rem;margin-right:4px;display:inline-flex}.market-filter-item:not(.active) .order[data-v-542fc917]{display:none}.market-filter-item .order[data-v-542fc917]{justify-content:center;align-items:center;width:1.75rem;display:inline-flex}.market-filter-item svg[data-v-542fc917]{max-width:1.125rem;height:1rem}.market-filter-item .text[data-v-542fc917],.market-filter-item .count[data-v-542fc917]{font-size:14px;font-weight:500;line-height:20px}.market-filter-item .count[data-v-542fc917]{opacity:.7;margin-right:4px;font-size:12px}.market-filter-item .spacer[data-v-542fc917]{flex:1}.cat-adapter[data-v-0e838db4]{--c:#38bdf8}.cat-general[data-v-0e838db4]{--c:#4ade80}.cat-extension[data-v-0e838db4]{--c:#a78bfa}.cat-webui[data-v-0e838db4]{--c:#fb923c}.cat-manage[data-v-0e838db4]{--c:#facc15}.cat-preset[data-v-0e838db4]{--c:#60a5fa}.cat-image[data-v-0e838db4]{--c:#f472b6}.cat-media[data-v-0e838db4]{--c:#e879f9}.cat-tool[data-v-0e838db4]{--c:#94a3b8}.cat-life[data-v-0e838db4]{--c:#34d399}.cat-ai[data-v-0e838db4]{--c:#818cf8}.cat-meme[data-v-0e838db4]{--c:#fbbf24}.cat-game[data-v-0e838db4]{--c:#f87171}.cat-gametool[data-v-0e838db4]{--c:#c084fc}.cat-other[data-v-0e838db4]{--c:#64748b}.market-package[data-v-0e838db4]{box-sizing:border-box;background-color:var(--k-card-bg);border:1px solid var(--k-color-border);contain:layout paint style;border-radius:12px;width:100%;max-width:540px;height:calc(12.5rem + 2px);margin:0;padding:1rem 1.25rem;transition:border-color .18s,box-shadow .18s,background-color .18s;position:relative}.market-package[data-v-0e838db4]:hover{border-color:var(--k-color-primary);box-shadow:0 4px 12px #0000000f}.market-package .market-icon[data-v-0e838db4]{height:1em;display:inline}.market-package .header[data-v-0e838db4],.market-package .footer[data-v-0e838db4]{flex:none}.market-package .header[data-v-0e838db4]{position:relative}.market-package .header .left[data-v-0e838db4]{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--c) 35%, var(--k-color-border));background:linear-gradient(135deg, color-mix(in srgb, var(--c) 18%, var(--k-card-bg)), color-mix(in srgb, var(--c) 10%, var(--k-card-bg)));width:3.5rem;height:3.5rem;transition:var(--color-transition);border-radius:10px}.market-package .header .left svg[data-v-0e838db4]{height:1.75rem;color:var(--c)}.market-package .header h2[data-v-0e838db4]{align-items:center;margin:0;font-size:1.125rem;font-weight:600;line-height:1.2;display:flex}.market-package .header h2 .title[data-v-0e838db4]{flex:0 auto;line-height:1.5rem;display:inline-block}.market-package .header .heartbeat[data-v-0e838db4]{height:1.5rem;color:var(--k-text-light);align-items:center;gap:5px;font-size:12px;display:inline-flex}.market-package .header .heartbeat .market-icon[data-v-0e838db4]{width:12px;height:12px;color:color-mix(in srgb, #eb4d55 var(--heart-mix,0%), var(--k-text-light));opacity:var(--heart-opacity,.5);filter:drop-shadow(0 0 calc(var(--heart-glow,0) * 4px) rgb(235, 77, 85, calc(var(--heart-glow,0) * .45)));flex:none;transition:color .3s,opacity .3s}.market-package .badge-float[data-v-0e838db4]{position:absolute;bottom:2.5rem;right:1.25rem}.market-package .badge-pill[data-v-0e838db4]{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--k-color-success) 20%, transparent);background-color:color-mix(in srgb, var(--k-color-success) 10%, transparent);height:20px;color:var(--k-color-success);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:10px;align-items:center;gap:3px;padding:0 6px;font-size:12px;font-weight:500;line-height:20px;display:inline-flex}.market-package .badge-pill .market-icon[data-v-0e838db4]{width:12px;height:12px}.market-package .badge-pill.preview[data-v-0e838db4]{border-color:color-mix(in srgb, var(--k-color-warning) 20%, transparent);background-color:color-mix(in srgb, var(--k-color-warning) 10%, transparent);color:var(--k-color-warning)}.market-package .badge-pill.insecure[data-v-0e838db4]{border-color:color-mix(in srgb, var(--k-color-danger) 20%, transparent);background-color:color-mix(in srgb, var(--k-color-danger) 10%, transparent);color:var(--k-color-danger)}.market-package .desc[data-v-0e838db4]{color:var(--k-text-light);word-break:break-word;text-overflow:ellipsis;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:auto;margin:0;font-size:14px;line-height:1.6;display:-webkit-box;overflow:hidden}.market-package .footer[data-v-0e838db4]{cursor:default;height:1.5rem;color:var(--k-text-light);align-items:center;gap:.5rem;margin-bottom:-.25rem;font-size:13px;transition:color .3s;display:flex;overflow:hidden}.market-package .footer[data-v-0e838db4]>*{flex:none}.market-package .footer .spacer[data-v-0e838db4]{flex:0 2 .5rem}.market-package .footer .long-spacer[data-v-0e838db4]{flex:auto}.market-package .footer .market-icon[data-v-0e838db4]{vertical-align:-1px;width:16px;height:12px;margin-right:6px}.market-package .footer .avatars[data-v-0e838db4]{gap:.25rem;display:flex}.market-package .footer .avatars .avatar[data-v-0e838db4]{cursor:pointer;border-radius:100%;width:1.5rem;height:1.5rem}.market-package .footer .avatars .avatar img[data-v-0e838db4]{vertical-align:middle;border-radius:100%;width:1.5rem;height:1.5rem}.market-package .footer .avatars .avatar.fallback[data-v-0e838db4]{box-sizing:border-box;background:linear-gradient(135deg, color-mix(in srgb, var(--c) 30%, var(--k-card-bg)), color-mix(in srgb, var(--c) 12%, var(--k-card-bg)));color:color-mix(in srgb, var(--c) 80%, var(--k-text-dark));justify-content:center;align-items:center;font-size:.68rem;font-weight:700;display:inline-flex}.market-package .footer .avatars .avatar.fallback[data-v-0e838db4]:before{content:attr(data-initial)}@media (width<=420px){.market-package[data-v-0e838db4]{height:auto;min-height:11rem;padding:.82rem .9rem}.market-package .header .left[data-v-0e838db4]{width:3rem;height:3rem}.market-package h2[data-v-0e838db4]{font-size:1rem}.market-package .badge-float[data-v-0e838db4]{bottom:2.3rem;right:.9rem}.market-package .footer[data-v-0e838db4]{flex-wrap:wrap;height:auto}.market-package .footer .long-spacer[data-v-0e838db4]{display:none}}.package-list[data-v-e3691166]{gap:var(--card-margin);flex:1 0 auto;grid-template-columns:repeat(auto-fill,minmax(336px,1fr));justify-items:center;display:grid}.pagination[data-v-e3691166]{margin:var(--card-margin) 0;justify-content:center}.k-empty[data-v-e3691166]{flex:1 0 auto}.search-box[data-v-ee66eeec]{border:1.5px solid var(--k-color-border);box-sizing:border-box;background-color:var(--k-card-bg);border-radius:2rem;align-items:center;width:100%;max-width:640px;margin:2rem auto 0;transition:border-color .2s,box-shadow .2s;display:flex;box-shadow:0 2px 12px #0000000f,0 1px 3px #0000000a}.search-box[data-v-ee66eeec]:focus-within{border-color:var(--k-color-primary);box-shadow:0 0 0 3px color-mix(in srgb, var(--k-color-primary) 15%, transparent), 0 2px 12px #0000000f, 0 1px 3px #0000000a}.search-container[data-v-ee66eeec]{flex-wrap:wrap;flex:auto;align-items:center;gap:8px 6px;padding:.75rem 0 .75rem 1.25rem;display:flex}.search-container input[data-v-ee66eeec]{box-sizing:border-box;min-width:10rem;height:1.25rem;color:inherit;background-color:#0000;border:none;outline:none;flex:auto;padding:0;font-size:.925rem}.search-action[data-v-ee66eeec]{cursor:pointer;flex-direction:column;flex:none;justify-content:center;align-items:center;width:3rem;height:2.5rem;display:flex}.search-action .market-icon[data-v-ee66eeec]{opacity:.45;height:1rem;transition:opacity .2s}.search-action:hover .market-icon[data-v-ee66eeec]{opacity:.85}.search-action:hover .market-icon.search[data-v-ee66eeec],.search-action:not(:hover) .market-icon.close[data-v-ee66eeec]{display:none}.search-word[data-v-ee66eeec]{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--k-color-primary) 25%, transparent);background-color:color-mix(in srgb, var(--k-color-primary) 12%, transparent);height:1.375rem;color:var(--k-color-primary);white-space:nowrap;vertical-align:baseline;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:6px;flex:none;padding:0 8px;font-size:12px;font-weight:500;line-height:calc(1.375rem - 2px);transition:opacity .3s,background-color .3s,border-color .3s;display:inline-block}.search-word.invalid[data-v-ee66eeec]{opacity:.5;text-decoration:line-through}.search-word.invalid[data-v-ee66eeec]:hover{opacity:1}@media (width<=420px){.search-box[data-v-ee66eeec]{border-radius:12px}}.page-market .layout-main .el-scrollbar__view{padding:0 var(--card-margin);flex-direction:column;min-height:100%;display:flex}.page-market .layout-left .market-filter-group{margin:1.5rem 0;padding:0 1rem}.page-market .layout-left h2{letter-spacing:.08em;text-transform:uppercase;color:var(--k-text-light);opacity:.7;margin:0;padding:6px .5rem;font-size:11px;font-weight:700}.market-loading{flex-direction:column;flex:1 0 auto;justify-content:center;align-items:center;gap:2rem;min-height:50vh;display:flex}.market-loading .el-loading-spinner{margin-top:0}.market-slow.k-comment{max-width:640px}.market-hint{width:100%;color:var(--el-text-color-regular);font-size:var(--el-font-size-base);font-weight:var(--el-font-weight-primary);margin:1rem 0 .75rem;transition:color .3s}.market-container .k-button{margin-left:1rem;padding:.35em .85em;transform:translateY(-1px)}.market-error.k-comment{margin-left:2rem;margin-right:2rem}.page-market .el-scrollbar__thumb{background-clip:content-box;background-color:color-mix(in srgb, var(--k-color-primary) 26%, var(--fg3));border:2px solid #0000;border-radius:999px;min-height:32px}.page-market .el-scrollbar__thumb:hover{background-color:color-mix(in srgb, var(--k-color-primary) 44%, var(--fg3))}.k-status .el-progress-bar{width:120px;margin-right:2px}.dialog-config-fork .el-dialog__header .el-dialog__title{color:var(--fg1);flex:none;margin-right:.5rem;font-weight:500}.dialog-config-fork .status-light{margin-right:.75rem}.dialog-config-fork .actions{justify-content:flex-end;align-items:center;gap:0 .5rem;display:flex}.dialog-config-fork .action{cursor:pointer;width:1.25rem;color:var(--fg2);transition:var(--color-transition);justify-content:center;display:inline-flex}.dialog-config-fork .action:hover{color:var(--fg1)}.dialog-config-fork .el-dialog__footer{justify-content:space-between;align-items:center;font-size:.9em;display:flex}.modifier,.plugin-view .markdown.usage{margin-bottom:2rem}.plugin-view .markdown.usage h2{font-size:1.25rem}.plugin-tree{width:100%;height:100%;overflow:auto}.plugin-tree .el-scrollbar__view{padding:1rem 0;line-height:2.25rem}.plugin-tree .search{padding:0 1.5rem}.plugin-tree .k-icon-filter{height:15px}.plugin-tree .el-tree-node.is-group>.el-tree-node__content{font-weight:700}.plugin-tree .el-tree-node__content .item{flex:1;justify-content:space-between;align-items:center;height:100%;display:flex;overflow:hidden}.plugin-tree .el-tree-node__content .label{text-overflow:ellipsis;transition:var(--color-transition);overflow:hidden}.plugin-tree .el-tree-node__content .right{height:100%;margin:0 1.5rem 0 .5rem}.end{margin-right:.5rem}.config-header{margin:0 0 2rem;font-size:1.375rem;line-height:2rem}.config-header .k-button{float:right}.plugin-view .k-content>:first-child{margin-top:0}.plugin-select .el-dialog__header{border-bottom:1px solid var(--k-color-divider);justify-content:space-between;align-items:center;margin-right:0;padding:12px 20px;display:flex}.plugin-select .el-dialog__header button{top:2px}.plugin-select .el-dialog__header .title{flex:none}.plugin-select .el-dialog__header .el-input{width:220px;height:2rem;display:inline-block}.plugin-select .el-dialog__body{height:50vh;padding:0;display:flex}.plugin-select .el-dialog__body .tabs{border-right:1px solid var(--k-color-divider);flex:none;width:7.5rem;font-size:15px}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs{width:3rem}}.plugin-select .el-dialog__body .tabs .el-scrollbar__view{padding:.5rem 0}.plugin-select .el-dialog__body .tabs .tab-item{cursor:pointer;height:2rem;transition:var(--color-transition);justify-content:center;align-items:center;padding:0 1rem;font-size:.875rem;display:flex}.plugin-select .el-dialog__body .tabs .tab-item:hover{background-color:var(--k-hover-bg)}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs .tab-item{padding:0}}.plugin-select .el-dialog__body .tabs .tab-item .market-icon{width:1.25rem;height:1rem}.plugin-select .el-dialog__body .tabs .tab-item.active{color:var(--primary)}.plugin-select .el-dialog__body .tabs .tab-item .title{width:3.5rem;margin-left:.5rem}@media screen and (width<=768px){.plugin-select .el-dialog__body .tabs .tab-item .title{display:none}}.plugin-select .el-dialog__body .content{flex:auto}.plugin-select .el-dialog__body .content .package{cursor:pointer;transition:var(--color-transition);padding:.5rem 1rem}.plugin-select .el-dialog__body .content .package h3{margin:0 0 .25rem;font-size:16px}.plugin-select .el-dialog__body .content .package p{margin:0;font-size:14px}.plugin-select .el-dialog__body .content .package:hover{background-color:var(--k-hover-bg)}.absolute{position:absolute}.relative{position:relative}.grid{display:grid}.my-8{margin-top:2rem;margin-bottom:2rem}.inline{display:inline}.block{display:block}.inline-block{display:inline-block}.hidden{display:none}.h2{height:.5rem}.h3{height:.75rem}.flex{display:flex}.inline-flex{display:inline-flex}.shrink-0{flex-shrink:0}.grow-1{flex-grow:1}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-4{column-gap:1rem}.gap-y-2{row-gap:.5rem}.overflow-hidden{overflow:hidden}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.b,.border{border-width:1px}.px{padding-left:1rem;padding-right:1rem}.pl-8{padding-left:2rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.shadow{--un-shadow:var(--un-shadow-inset) 0 1px 3px 0 var(--un-shadow-color,#0000001a),var(--un-shadow-inset) 0 1px 2px -1px var(--un-shadow-color,#0000001a);box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow)}.outline{outline-style:solid}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease{transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog-config-fork .status-light,.plugin-tree .status-light{width:.625rem;height:.625rem;transition:var(--color-transition);border-radius:100%;display:inline-block}.dialog-config-fork .status-light.active,.plugin-tree .status-light.active{background-color:var(--k-color-success)}.dialog-config-fork .status-light.pending,.plugin-tree .status-light.pending{background-color:var(--k-color-warning)}.dialog-config-fork .status-light.loading,.plugin-tree .status-light.loading{background-color:var(--k-color-warning);animation:1s infinite status-flash}.dialog-config-fork .status-light.failed,.plugin-tree .status-light.failed{background-color:var(--k-color-danger)}.dialog-config-fork .status-light.disabled:not(.ignore-disabled),.plugin-tree .status-light.disabled:not(.ignore-disabled){opacity:.5;background-color:var(--k-color-disabled)}@keyframes status-flash{0%,to{opacity:0}50%{opacity:1}}
|
|
2
2
|
/*$vite$:1*/
|
package/lib/index.d.ts
CHANGED
|
@@ -45,6 +45,20 @@ declare class Installer extends Service {
|
|
|
45
45
|
exec(args: string[]): Promise<number>;
|
|
46
46
|
override(deps: Dict<string | null>): Promise<void>;
|
|
47
47
|
private _install;
|
|
48
|
+
/**
|
|
49
|
+
* 安装完整性校验:从本次安装的包出发递归纯 fs 探测依赖可达性,返回
|
|
50
|
+
* 「包: 缺失依赖」描述列表。背景是 Bun isolated 布局的增量安装缺陷
|
|
51
|
+
* (2026-09-07 实证):升级插件时包目录 hash 变化,而其依赖的解析
|
|
52
|
+
* 结果未变,bun 的增量安装跳过新包目录内的依赖链接建立——插件入口
|
|
53
|
+
* (顶层 symlink)可加载,内部依赖的 require 却炸 MODULE_NOT_FOUND;
|
|
54
|
+
* 此时补跑一次普通 bun install,bun 按磁盘实际状态检测到包不完整
|
|
55
|
+
* 即重建链接(秒级)。全程只走 existsSync / readFileSync /
|
|
56
|
+
* realpathSync,不触碰解析 API(防父目录快照缓存,与
|
|
57
|
+
* resolvePackageJson 同一纪律)。peer / optional 依赖由宿主或按需
|
|
58
|
+
* 提供不入校验;workspace / alias 等非 semver 声明的落盘名与键名无
|
|
59
|
+
* 直接映射,同样跳过。
|
|
60
|
+
*/
|
|
61
|
+
private _findMissingDeps;
|
|
48
62
|
private _getLocalDeps;
|
|
49
63
|
install(deps: Dict<string | null>, forced?: boolean): Promise<number>;
|
|
50
64
|
static Config: Schema<Installer.Config>;
|
package/lib/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { join, resolve } from "node:path";
|
|
1
|
+
import { dirname, join, resolve } from "node:path";
|
|
2
2
|
import { Logger, Schema, Service, Time, defineProperty, pick, sleep, valueMap } from "@koishi-ce/koishi";
|
|
3
3
|
import { compare, gt, satisfies, valid } from "semver";
|
|
4
4
|
import { DataService } from "@koishi-ce/console";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
5
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import Scanner, { isResidentInCache, mapLimit, resolvePackageJson } from "@koishi-ce/registry";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
@@ -62,6 +62,26 @@ const logger$2 = new Logger("market");
|
|
|
62
62
|
function isGuardedRequest(request) {
|
|
63
63
|
return request?.startsWith("workspace:") === true || request?.startsWith("npm:@koishi-ce") === true;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* 从 fromDir 沿 node_modules 链纯 fs 探测依赖包,命中返回其真实目录。
|
|
67
|
+
* realpath 化是 isolated 布局的关键:顶层条目是 symlink,包的依赖链接
|
|
68
|
+
* 挂在 .bun 真实目录的同级 node_modules,从链接路径向上爬会错误地查
|
|
69
|
+
* 顶层(isolated 不提升传递依赖)。
|
|
70
|
+
*/
|
|
71
|
+
function probePackage(fromDir, name) {
|
|
72
|
+
let dir = resolve(fromDir);
|
|
73
|
+
for (;;) {
|
|
74
|
+
const manifestPath = join(dir, "node_modules", name, "package.json");
|
|
75
|
+
if (existsSync(manifestPath)) try {
|
|
76
|
+
return dirname(realpathSync(manifestPath));
|
|
77
|
+
} catch {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const parent = dirname(dir);
|
|
81
|
+
if (parent === dir) return void 0;
|
|
82
|
+
dir = parent;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
65
85
|
/** 从单个 .npmrc 文件提取 registry 配置项;文件不存在或读取出错一律视为未配置 */
|
|
66
86
|
function readNpmrcRegistry(file) {
|
|
67
87
|
try {
|
|
@@ -244,6 +264,50 @@ var Installer = class extends Service {
|
|
|
244
264
|
if (this.endpoint) args.push("--registry", this.endpoint);
|
|
245
265
|
return this.exec(args);
|
|
246
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* 安装完整性校验:从本次安装的包出发递归纯 fs 探测依赖可达性,返回
|
|
269
|
+
* 「包: 缺失依赖」描述列表。背景是 Bun isolated 布局的增量安装缺陷
|
|
270
|
+
* (2026-09-07 实证):升级插件时包目录 hash 变化,而其依赖的解析
|
|
271
|
+
* 结果未变,bun 的增量安装跳过新包目录内的依赖链接建立——插件入口
|
|
272
|
+
* (顶层 symlink)可加载,内部依赖的 require 却炸 MODULE_NOT_FOUND;
|
|
273
|
+
* 此时补跑一次普通 bun install,bun 按磁盘实际状态检测到包不完整
|
|
274
|
+
* 即重建链接(秒级)。全程只走 existsSync / readFileSync /
|
|
275
|
+
* realpathSync,不触碰解析 API(防父目录快照缓存,与
|
|
276
|
+
* resolvePackageJson 同一纪律)。peer / optional 依赖由宿主或按需
|
|
277
|
+
* 提供不入校验;workspace / alias 等非 semver 声明的落盘名与键名无
|
|
278
|
+
* 直接映射,同样跳过。
|
|
279
|
+
*/
|
|
280
|
+
_findMissingDeps(deps) {
|
|
281
|
+
const problems = [];
|
|
282
|
+
const visited = /* @__PURE__ */ new Set();
|
|
283
|
+
const walk = (dir, label) => {
|
|
284
|
+
if (visited.has(dir)) return;
|
|
285
|
+
visited.add(dir);
|
|
286
|
+
let manifest;
|
|
287
|
+
try {
|
|
288
|
+
manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
|
|
289
|
+
} catch {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
for (const [dep, request] of Object.entries(manifest.dependencies ?? {})) {
|
|
293
|
+
if (request.includes(":")) continue;
|
|
294
|
+
const depDir = probePackage(dir, dep);
|
|
295
|
+
if (!depDir) {
|
|
296
|
+
problems.push(`${label} 的依赖 ${dep} 未被链接`);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
walk(depDir, `${label} → ${dep}`);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
for (const name in deps) {
|
|
303
|
+
const request = deps[name];
|
|
304
|
+
if (!request || request.includes(":")) continue;
|
|
305
|
+
const dir = probePackage(this.cwd, name);
|
|
306
|
+
if (!dir) continue;
|
|
307
|
+
walk(dir, name);
|
|
308
|
+
}
|
|
309
|
+
return problems;
|
|
310
|
+
}
|
|
247
311
|
_getLocalDeps(override) {
|
|
248
312
|
return valueMap(override, (request, name) => {
|
|
249
313
|
const dep = { request };
|
|
@@ -269,6 +333,13 @@ var Installer = class extends Service {
|
|
|
269
333
|
if (shouldInstall) {
|
|
270
334
|
const code = await this._install();
|
|
271
335
|
if (code) return code;
|
|
336
|
+
const missing = this._findMissingDeps(deps);
|
|
337
|
+
if (missing.length) {
|
|
338
|
+
logger$2.warn(`检测到增量安装未建立部分依赖链接(isolated 布局已知缺陷),正在补装: ${missing.join("; ")}`);
|
|
339
|
+
const retry = await this._install();
|
|
340
|
+
if (retry) return retry;
|
|
341
|
+
if (this._findMissingDeps(deps).length) logger$2.warn("自动补装后依赖链接仍不完整,请在项目根目录运行 bun install --force 并重启 koishi");
|
|
342
|
+
}
|
|
272
343
|
}
|
|
273
344
|
this.refresh();
|
|
274
345
|
const newDeps = await this.getDeps();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koishi-ce/plugin-market",
|
|
3
3
|
"description": "Manage your bots and plugins with console",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -66,7 +66,9 @@
|
|
|
66
66
|
"@koishi-ce/plugin-config": "^1.1.2",
|
|
67
67
|
"@koishijs/market": "^4.2.10",
|
|
68
68
|
"@types/semver": "^7.5.8",
|
|
69
|
+
"@types/spark-md5": "^3.0.4",
|
|
69
70
|
"@vueuse/core": "^14.4.0",
|
|
71
|
+
"spark-md5": "^3.0.2",
|
|
70
72
|
"vue": "^3.5.12",
|
|
71
73
|
"vue-router": "^5.2.0"
|
|
72
74
|
},
|
|
@@ -82,14 +82,14 @@ const http = (await import("@koishi-ce/plugin-http"))
|
|
|
82
82
|
const { isResidentInCache } = await import(
|
|
83
83
|
"@koishi-ce/registry"
|
|
84
84
|
);
|
|
85
|
-
const market = await import("
|
|
85
|
+
const market = await import("./node/index.ts");
|
|
86
86
|
const { default: Installer } = await import(
|
|
87
|
-
"
|
|
87
|
+
"./node/installer.ts"
|
|
88
88
|
);
|
|
89
89
|
const mockPlugin = (await import("@koishi-ce/plugin-mock"))
|
|
90
90
|
.default;
|
|
91
91
|
// 加载包入口占位文件(纯 re-export,无独立逻辑),保证 src 全量被加载
|
|
92
|
-
await import("
|
|
92
|
+
await import("./index.ts");
|
|
93
93
|
|
|
94
94
|
/** 控制台服务桩:仅实现入口登记所需的最小面。 */
|
|
95
95
|
class FakeConsole extends Console {
|
|
@@ -493,6 +493,108 @@ describe("Installer 安装链路", () => {
|
|
|
493
493
|
expect(code).toBe(-1);
|
|
494
494
|
});
|
|
495
495
|
|
|
496
|
+
/** 在临时 node_modules 落盘一个带 dependencies 声明的校验用包 */
|
|
497
|
+
function placeLinkcheckPkg(
|
|
498
|
+
dependencies: Record<string, string>,
|
|
499
|
+
) {
|
|
500
|
+
const name = "koishi-plugin-linkcheck";
|
|
501
|
+
const pkgDir = join(tmp, "node_modules", name);
|
|
502
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
503
|
+
writeFileSync(
|
|
504
|
+
join(pkgDir, "package.json"),
|
|
505
|
+
JSON.stringify({
|
|
506
|
+
name,
|
|
507
|
+
version: "1.0.0",
|
|
508
|
+
dependencies,
|
|
509
|
+
}),
|
|
510
|
+
);
|
|
511
|
+
return pkgDir;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
itQuiet(
|
|
515
|
+
"装后依赖链接完整时不触发补装",
|
|
516
|
+
async () => {
|
|
517
|
+
nextExitCode = 0;
|
|
518
|
+
spawnCalls.length = 0;
|
|
519
|
+
const pkgDir = placeLinkcheckPkg({
|
|
520
|
+
"linkcheck-dep": "^1.0.0",
|
|
521
|
+
});
|
|
522
|
+
const depDir = join(
|
|
523
|
+
tmp,
|
|
524
|
+
"node_modules",
|
|
525
|
+
"linkcheck-dep",
|
|
526
|
+
);
|
|
527
|
+
mkdirSync(depDir, { recursive: true });
|
|
528
|
+
writeFileSync(
|
|
529
|
+
join(depDir, "package.json"),
|
|
530
|
+
JSON.stringify({
|
|
531
|
+
name: "linkcheck-dep",
|
|
532
|
+
version: "1.0.0",
|
|
533
|
+
}),
|
|
534
|
+
);
|
|
535
|
+
try {
|
|
536
|
+
const code = await app.installer.install(
|
|
537
|
+
{ "koishi-plugin-linkcheck": "^1.0.0" },
|
|
538
|
+
true,
|
|
539
|
+
);
|
|
540
|
+
expect(code).toBe(0);
|
|
541
|
+
expect(spawnCalls.length).toBe(1);
|
|
542
|
+
} finally {
|
|
543
|
+
rmSync(pkgDir, { recursive: true, force: true });
|
|
544
|
+
rmSync(depDir, { recursive: true, force: true });
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
15000,
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
itQuiet(
|
|
551
|
+
"包级依赖链接缺失时自动补装一次且不无限重试",
|
|
552
|
+
async () => {
|
|
553
|
+
nextExitCode = 0;
|
|
554
|
+
spawnCalls.length = 0;
|
|
555
|
+
// isolated 增量安装缺陷形态:包已落盘但声明的依赖未链接。
|
|
556
|
+
// 首装后校验命中补装一次;mock 安装不会真落盘依赖,二次校验
|
|
557
|
+
// 仍缺,只告警不再补装——总计恰好两次子进程调用
|
|
558
|
+
const pkgDir = placeLinkcheckPkg({
|
|
559
|
+
"linkcheck-missing": "^1.0.0",
|
|
560
|
+
});
|
|
561
|
+
try {
|
|
562
|
+
const code = await app.installer.install(
|
|
563
|
+
{ "koishi-plugin-linkcheck": "^1.0.0" },
|
|
564
|
+
true,
|
|
565
|
+
);
|
|
566
|
+
expect(code).toBe(0);
|
|
567
|
+
expect(spawnCalls.length).toBe(2);
|
|
568
|
+
} finally {
|
|
569
|
+
rmSync(pkgDir, { recursive: true, force: true });
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
15000,
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
itQuiet(
|
|
576
|
+
"alias 声明的依赖跳过链接校验",
|
|
577
|
+
async () => {
|
|
578
|
+
nextExitCode = 0;
|
|
579
|
+
spawnCalls.length = 0;
|
|
580
|
+
// alias 落盘名与键名无直接映射,不入校验,缺失也不触发补装
|
|
581
|
+
const pkgDir = placeLinkcheckPkg({
|
|
582
|
+
"linkcheck-alias": "npm:whatever@^1.0.0",
|
|
583
|
+
});
|
|
584
|
+
try {
|
|
585
|
+
const code = await app.installer.install(
|
|
586
|
+
{ "koishi-plugin-linkcheck": "^1.0.0" },
|
|
587
|
+
true,
|
|
588
|
+
);
|
|
589
|
+
expect(code).toBe(0);
|
|
590
|
+
expect(spawnCalls.length).toBe(1);
|
|
591
|
+
} finally {
|
|
592
|
+
rmSync(pkgDir, { recursive: true, force: true });
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
15000,
|
|
596
|
+
);
|
|
597
|
+
|
|
496
598
|
itQuiet(
|
|
497
599
|
"exec 收集子进程 stdout / stderr 输出行",
|
|
498
600
|
async () => {
|
package/src/node/installer.ts
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
// Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
3
|
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
existsSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
realpathSync,
|
|
9
|
+
} from "node:fs";
|
|
6
10
|
import { homedir } from "node:os";
|
|
7
|
-
import { join, resolve } from "node:path";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
12
|
import type {} from "@koishi-ce/console";
|
|
9
13
|
import {
|
|
10
14
|
type Context,
|
|
@@ -53,6 +57,37 @@ function isGuardedRequest(
|
|
|
53
57
|
);
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
/**
|
|
61
|
+
* 从 fromDir 沿 node_modules 链纯 fs 探测依赖包,命中返回其真实目录。
|
|
62
|
+
* realpath 化是 isolated 布局的关键:顶层条目是 symlink,包的依赖链接
|
|
63
|
+
* 挂在 .bun 真实目录的同级 node_modules,从链接路径向上爬会错误地查
|
|
64
|
+
* 顶层(isolated 不提升传递依赖)。
|
|
65
|
+
*/
|
|
66
|
+
function probePackage(
|
|
67
|
+
fromDir: string,
|
|
68
|
+
name: string,
|
|
69
|
+
): string | undefined {
|
|
70
|
+
let dir = resolve(fromDir);
|
|
71
|
+
for (;;) {
|
|
72
|
+
const manifestPath = join(
|
|
73
|
+
dir,
|
|
74
|
+
"node_modules",
|
|
75
|
+
name,
|
|
76
|
+
"package.json",
|
|
77
|
+
);
|
|
78
|
+
if (existsSync(manifestPath)) {
|
|
79
|
+
try {
|
|
80
|
+
return dirname(realpathSync(manifestPath));
|
|
81
|
+
} catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const parent = dirname(dir);
|
|
86
|
+
if (parent === dir) return undefined;
|
|
87
|
+
dir = parent;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
56
91
|
/** 从单个 .npmrc 文件提取 registry 配置项;文件不存在或读取出错一律视为未配置 */
|
|
57
92
|
function readNpmrcRegistry(
|
|
58
93
|
file: string,
|
|
@@ -404,6 +439,59 @@ class Installer extends Service {
|
|
|
404
439
|
return this.exec(args);
|
|
405
440
|
}
|
|
406
441
|
|
|
442
|
+
/**
|
|
443
|
+
* 安装完整性校验:从本次安装的包出发递归纯 fs 探测依赖可达性,返回
|
|
444
|
+
* 「包: 缺失依赖」描述列表。背景是 Bun isolated 布局的增量安装缺陷
|
|
445
|
+
* (2026-09-07 实证):升级插件时包目录 hash 变化,而其依赖的解析
|
|
446
|
+
* 结果未变,bun 的增量安装跳过新包目录内的依赖链接建立——插件入口
|
|
447
|
+
* (顶层 symlink)可加载,内部依赖的 require 却炸 MODULE_NOT_FOUND;
|
|
448
|
+
* 此时补跑一次普通 bun install,bun 按磁盘实际状态检测到包不完整
|
|
449
|
+
* 即重建链接(秒级)。全程只走 existsSync / readFileSync /
|
|
450
|
+
* realpathSync,不触碰解析 API(防父目录快照缓存,与
|
|
451
|
+
* resolvePackageJson 同一纪律)。peer / optional 依赖由宿主或按需
|
|
452
|
+
* 提供不入校验;workspace / alias 等非 semver 声明的落盘名与键名无
|
|
453
|
+
* 直接映射,同样跳过。
|
|
454
|
+
*/
|
|
455
|
+
private _findMissingDeps(
|
|
456
|
+
deps: Dict<string | null>,
|
|
457
|
+
): string[] {
|
|
458
|
+
const problems: string[] = [];
|
|
459
|
+
const visited = new Set<string>();
|
|
460
|
+
const walk = (dir: string, label: string) => {
|
|
461
|
+
if (visited.has(dir)) return;
|
|
462
|
+
visited.add(dir);
|
|
463
|
+
let manifest: LocalPackage;
|
|
464
|
+
try {
|
|
465
|
+
manifest = JSON.parse(
|
|
466
|
+
readFileSync(join(dir, "package.json"), "utf8"),
|
|
467
|
+
) as LocalPackage;
|
|
468
|
+
} catch {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
for (const [dep, request] of Object.entries(
|
|
472
|
+
manifest.dependencies ?? {},
|
|
473
|
+
)) {
|
|
474
|
+
if (request.includes(":")) continue;
|
|
475
|
+
const depDir = probePackage(dir, dep);
|
|
476
|
+
if (!depDir) {
|
|
477
|
+
problems.push(`${label} 的依赖 ${dep} 未被链接`);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
walk(depDir, `${label} → ${dep}`);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
for (const name in deps) {
|
|
484
|
+
const request = deps[name];
|
|
485
|
+
if (!request || request.includes(":")) continue;
|
|
486
|
+
const dir = probePackage(this.cwd, name);
|
|
487
|
+
// 顶层包未落盘属于安装失败,由退出码与后续加载告警兜底,
|
|
488
|
+
// 不属于「包已装但链接缺失」的补装场景
|
|
489
|
+
if (!dir) continue;
|
|
490
|
+
walk(dir, name);
|
|
491
|
+
}
|
|
492
|
+
return problems;
|
|
493
|
+
}
|
|
494
|
+
|
|
407
495
|
private _getLocalDeps(override: Dict<string | null>) {
|
|
408
496
|
return valueMap(override, (request, name) => {
|
|
409
497
|
const dep = { request } as Dependency;
|
|
@@ -443,6 +531,22 @@ class Installer extends Service {
|
|
|
443
531
|
if (shouldInstall) {
|
|
444
532
|
const code = await this._install();
|
|
445
533
|
if (code) return code;
|
|
534
|
+
// isolated 布局的增量安装可能漏建新包目录的依赖链接(机理
|
|
535
|
+
// 见 _findMissingDeps 注释):装完即校验,缺失时补跑一次
|
|
536
|
+
// 安装——bun 按磁盘实际状态重建链接,秒级自愈,无需人工
|
|
537
|
+
const missing = this._findMissingDeps(deps);
|
|
538
|
+
if (missing.length) {
|
|
539
|
+
logger.warn(
|
|
540
|
+
`检测到增量安装未建立部分依赖链接(isolated 布局已知缺陷),正在补装: ${missing.join("; ")}`,
|
|
541
|
+
);
|
|
542
|
+
const retry = await this._install();
|
|
543
|
+
if (retry) return retry;
|
|
544
|
+
if (this._findMissingDeps(deps).length) {
|
|
545
|
+
logger.warn(
|
|
546
|
+
"自动补装后依赖链接仍不完整,请在项目根目录运行 bun install --force 并重启 koishi",
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
446
550
|
}
|
|
447
551
|
|
|
448
552
|
this.refresh();
|