koishi-plugin-market-bundle-workbench 0.2.0-alpha.0 → 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,25 +1,234 @@
1
1
  # koishi-plugin-market-bundle-workbench
2
2
 
3
- `market-bundle-workbench` is a developer workbench for creating Koishi Market NEXT plugin bundles (`koishi-plugin-pa-*`).
3
+ Koishi 插件包制作与发布工作台。它面向插件作者,用一个固定向导完成 `koishi-plugin-pa-*` 插件包的创建、成员选择、预设配置审查、npm 校验、文件生成、压缩包下载和发布命令生成。
4
4
 
5
- It helps authors assemble a bundle manifest, validate npm metadata, generate `package.json` / `koishi.bundle` / README snippets, and run `npm pack --dry-run` before publishing.
5
+ 这个插件只负责“制作与发布准备”。插件包的识别、安装、成员配置分组和卸载管理由 [koishi-plugin-market-next](https://github.com/qinfeng365/koishi-plugin-market-next) 负责。
6
6
 
7
- The workbench is intentionally separate from `koishi-plugin-market-next`: Market NEXT installs and manages bundles, while this plugin helps developers build them.
7
+ ## 为什么需要它
8
8
 
9
- ## Features
9
+ Market NEXT 的插件包允许开发者把一组 Koishi 插件作为一个独立 npm 插件发布到市场中。典型场景包括:
10
10
 
11
- - Optional Console page, controlled by `enableWorkbench`.
12
- - Generate npm-valid bundle package metadata.
13
- - Validate package names, versions, semver ranges, duplicate members, self references, direct cycles, npm existence, and published versions.
14
- - Pick installed plugins as members or enter package names manually.
15
- - Edit required/optional members and preset config JSON.
16
- - Generate dry-run and publish commands without storing npm tokens.
11
+ - 整理一套实用插件,用户安装插件包后即可一次性安装全部成员。
12
+ - 发布小型插件生态,例如核心插件加多个外围插件。
13
+ - 为新用户提供预设组合,同时让高级用户在安装前选择成员和审查配置。
17
14
 
18
- ## Usage
15
+ 手写插件包容易出错:npm 包名必须小写、成员版本不能缺省、`market:package` keyword 容易忘、预设配置存在安全风险、版本是否已发布需要反复查。工作台把这些步骤收进一条可检查的发布流。
19
16
 
20
- 1. Install and enable this plugin in Koishi.
21
- 2. Turn on `enableWorkbench`.
22
- 3. Open **插件包工作台** in the Console.
23
- 4. Build the member list, validate, generate files, then run the suggested npm commands in your project.
17
+ ## 特性
24
18
 
25
- The first version does not publish packages directly. It only generates files and commands so authors can review the final output.
19
+ - 分步发布向导:项目、成员、配置审计、校验、生成与发布。
20
+ - 支持 `koishi-plugin-pa-*` 和 `@scope/koishi-plugin-pa-*` 插件包命名。
21
+ - 可从已安装插件选择成员,也可手动输入 npm 包名。
22
+ - 每个成员可设置包名、插件键、版本范围、必选/可选和预设配置。
23
+ - 预设配置支持 JSON 预览,并提示敏感字段。
24
+ - 校验 npm 包存在性、版本占用、成员版本范围、自引用、重复成员、直接循环和缺少 `market:package`。
25
+ - 生成 `package.json`、`koishi.bundle`、`README.md` 和 `lib/index.js`。
26
+ - 支持下载 npm-ready `.tgz`,由 `npm pack` 真实生成。
27
+ - 支持下载源码 `.zip`,便于开发者本地审查和二次编辑。
28
+ - 支持写入本地项目目录、预览覆盖差异和运行 `npm pack --dry-run`。
29
+ - 不保存 npm token,不代替用户执行 `npm publish`。
30
+
31
+ ## 安装
32
+
33
+ 在 Koishi 中安装:
34
+
35
+ ```bash
36
+ npm install koishi-plugin-market-bundle-workbench@alpha
37
+ ```
38
+
39
+ 如果你希望在 Koishi 控制台的插件市场里安装,推荐同时安装 Market NEXT:
40
+
41
+ ```bash
42
+ npm install koishi-plugin-market-next@alpha
43
+ npm install koishi-plugin-market-bundle-workbench@alpha
44
+ ```
45
+
46
+ 启用插件后,在配置页打开:
47
+
48
+ ```yaml
49
+ enableWorkbench: true
50
+ ```
51
+
52
+ 默认不开启工作台页面,避免普通用户的控制台出现开发者工具入口。
53
+
54
+ ## 使用流程
55
+
56
+ 1. 打开 Koishi 控制台中的“插件包工作台”。
57
+ 2. 在“项目”步骤填写插件包名、版本、显示名、描述、keywords、dist-tag 和可选项目目录。
58
+ 3. 在“成员”步骤选择已安装插件,或手动输入成员 npm 包名。
59
+ 4. 在“配置审计”步骤检查每个成员的预设配置。含 `command`、`script`、`exec`、`path`、`token`、`sql`、`url` 等字段时应特别审查。
60
+ 5. 在“校验”步骤运行 npm 与清单校验,确认没有 error。
61
+ 6. 在“生成与发布”步骤生成文件,并选择一种发布方式。
62
+
63
+ ## 推荐发布方式
64
+
65
+ ### 下载 npm 发布包
66
+
67
+ 这是推荐方式。工作台会创建临时目录,写入生成文件,执行真实的:
68
+
69
+ ```bash
70
+ npm pack --json
71
+ ```
72
+
73
+ 然后把生成的 `.tgz` 返回给浏览器下载。开发者在本机执行:
74
+
75
+ ```bash
76
+ npm publish ./koishi-plugin-pa-example-0.1.0.tgz --tag alpha
77
+ ```
78
+
79
+ scoped 包需要公开发布:
80
+
81
+ ```bash
82
+ npm publish ./scope-koishi-plugin-pa-example-0.1.0.tgz --tag alpha --access public
83
+ ```
84
+
85
+ 这种方式最接近真实 npm 产物,适合确认后直接发布。
86
+
87
+ ### 下载源码 zip
88
+
89
+ 源码 zip 包含同样的生成文件:
90
+
91
+ - `package.json`
92
+ - `README.md`
93
+ - `lib/index.js`
94
+
95
+ 下载后可以解压、审查、修改,再在本机运行:
96
+
97
+ ```bash
98
+ npm pack --dry-run
99
+ npm publish --tag alpha
100
+ ```
101
+
102
+ ### 写入本地项目
103
+
104
+ 如果你已经准备了一个本地插件包项目,可以填写项目目录并使用“写入项目”。工作台默认不会覆盖已有文件,除非显式勾选允许覆盖。写入后可直接在该目录运行:
105
+
106
+ ```bash
107
+ npm pack --dry-run
108
+ npm publish --tag alpha
109
+ ```
110
+
111
+ ## 插件包格式
112
+
113
+ 真实 npm 包名必须使用小写:
114
+
115
+ - `koishi-plugin-pa-xxx`
116
+ - `@scope/koishi-plugin-pa-xxx`
117
+
118
+ `koishi-plugin-PA-xxx` 只能作为概念写法,不是合法 npm 包名。
119
+
120
+ 推荐添加 keyword:
121
+
122
+ ```json
123
+ {
124
+ "keywords": ["koishi", "plugin", "market:package"]
125
+ }
126
+ ```
127
+
128
+ 核心清单位于 `package.json` 的 `koishi.bundle`:
129
+
130
+ ```json
131
+ {
132
+ "koishi": {
133
+ "bundle": {
134
+ "label": "Dialogue 插件包",
135
+ "description": "一组对话系统相关插件。",
136
+ "members": [
137
+ {
138
+ "package": "koishi-plugin-dialogue",
139
+ "plugin": "dialogue",
140
+ "version": "^1.0.0",
141
+ "required": true,
142
+ "config": {}
143
+ }
144
+ ]
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ `members[].version` 必填。工作台不会默认使用 `latest`,因为这会让用户安装到插件包作者没有确认过的破坏性版本。
151
+
152
+ ## 生成的包会做什么
153
+
154
+ 插件包自身是一个很薄的 Koishi 插件入口:
155
+
156
+ ```js
157
+ 'use strict'
158
+
159
+ exports.name = 'pa-example'
160
+
161
+ exports.apply = function apply() {
162
+ // This package is a Market NEXT plugin bundle manifest.
163
+ // Runtime behavior is provided by the bundle members.
164
+ }
165
+ ```
166
+
167
+ 也就是说,插件包本身不应该承载业务逻辑。它的职责是把成员清单和版本约束发布到 npm,并交给 Market NEXT 展开安装和管理。
168
+
169
+ ## 安全边界
170
+
171
+ 工作台刻意不做这些事:
172
+
173
+ - 不保存 npm token。
174
+ - 不在服务器端执行 `npm publish`。
175
+ - 不绕过 npm 登录态和二次确认。
176
+ - 不默认启用成员插件。
177
+ - 不把预设配置静默注入用户环境。
178
+
179
+ 原因很简单:插件包可能包含多个成员和预设配置,发布动作也会影响公开 npm 包。最终发布应该发生在开发者自己的本机 npm 环境中。
180
+
181
+ ## 配置项
182
+
183
+ | 配置项 | 默认值 | 说明 |
184
+ | --- | --- | --- |
185
+ | `enableWorkbench` | `false` | 是否启用控制台“插件包工作台”页面。 |
186
+ | `npmRegistry` | `https://registry.npmjs.org` | 用于校验 npm 包信息的 registry。 |
187
+ | `defaultDistTag` | `alpha` | 生成发布命令时使用的默认 dist-tag。 |
188
+ | `allowPublishCommand` | `false` | 是否显示 `npm publish` 命令。插件仍不会代为执行发布。 |
189
+
190
+ ## Console 事件
191
+
192
+ 工作台注册以下只面向控制台的事件:
193
+
194
+ | 事件 | 作用 |
195
+ | --- | --- |
196
+ | `bundle-workbench/npm-info(name)` | 查询 npm 包是否存在、版本、作者、维护者和 keywords。 |
197
+ | `bundle-workbench/validate(draft)` | 校验插件包草稿,返回 error / warning / info。 |
198
+ | `bundle-workbench/generate(draft)` | 生成 `package.json`、`koishi.bundle`、`lib/index.js`、README 和发布命令。 |
199
+ | `bundle-workbench/download-archive(draft, type)` | 生成并下载 `npm-tgz` 或 `source-zip`。 |
200
+ | `bundle-workbench/write-files(projectPath, draft, options)` | 写入本地项目目录,支持 dry-run 和覆盖控制。 |
201
+ | `bundle-workbench/pack-dry-run(projectPath)` | 在项目目录运行 `npm pack --dry-run`。 |
202
+
203
+ ## 本地开发
204
+
205
+ ```bash
206
+ npm install
207
+ npm run build
208
+ npm run check:package
209
+ ```
210
+
211
+ 脚本说明:
212
+
213
+ - `npm run build`:构建 TypeScript、后端入口和控制台前端产物。
214
+ - `npm run check:package`:运行 `npm pack --dry-run`,确认发布包内容。
215
+
216
+ ## CI 与发布
217
+
218
+ 仓库包含两个 GitHub Actions workflow:
219
+
220
+ - `CI`:在 push / pull request 时运行安装、构建和打包检查。
221
+ - `Publish`:在 `v*` tag 或手动触发时发布 npm,发布前检查 tag/input 版本必须等于 `package.json`。
222
+
223
+ 发布 alpha 版本时建议:
224
+
225
+ ```bash
226
+ npm version 0.2.0-alpha.2 --no-git-tag-version
227
+ npm run build
228
+ npm run check:package
229
+ npm publish --tag alpha
230
+ ```
231
+
232
+ ## License
233
+
234
+ AGPL-3.0
@@ -26,6 +26,20 @@ export interface MemberView {
26
26
  autoPlugin: boolean
27
27
  }
28
28
 
29
+ export interface InstalledOption {
30
+ name: string
31
+ shortname: string
32
+ version: string
33
+ label: string
34
+ description: string
35
+ hasSchema: boolean
36
+ added: boolean
37
+ verified: boolean
38
+ insecure: boolean
39
+ deprecated: boolean
40
+ category?: string
41
+ }
42
+
29
43
  function packagesIndex() {
30
44
  return ((store as any).packages ?? {}) as Record<string, any>
31
45
  }
@@ -34,6 +48,18 @@ function marketIndex() {
34
48
  return ((store as any).market?.data ?? {}) as Record<string, any>
35
49
  }
36
50
 
51
+ function pickDescription(value: unknown) {
52
+ if (typeof value === 'string') return value.trim()
53
+ if (!value || typeof value !== 'object') return ''
54
+ const object = value as Record<string, unknown>
55
+ for (const key of ['zh-CN', 'zh', 'en-US', 'en']) {
56
+ const text = object[key]
57
+ if (typeof text === 'string' && text.trim()) return text.trim()
58
+ }
59
+ const fallback = Object.values(object).find(item => typeof item === 'string' && item.trim())
60
+ return typeof fallback === 'string' ? fallback.trim() : ''
61
+ }
62
+
37
63
  export function useBundleDraft() {
38
64
  const draft = reactive({
39
65
  packageName: 'koishi-plugin-pa-demo',
@@ -49,14 +75,31 @@ export function useBundleDraft() {
49
75
  const packageNameOk = computed(() => isBundlePackageName(draft.packageName))
50
76
  const presetCount = computed(() => members.filter(hasPresetConfig).length)
51
77
 
52
- const installedOptions = computed(() => {
78
+ const installedOptions = computed<InstalledOption[]>(() => {
53
79
  return Object.values(packagesIndex())
54
80
  .filter((item: any) => isPluginPackageName(item?.package?.name))
55
- .sort((a: any, b: any) => a.package.name.localeCompare(b.package.name))
56
- .map((item: any) => ({
57
- name: item.package.name,
58
- label: `${item.package.name}@${item.package.version}`,
59
- }))
81
+ .map((item: any) => {
82
+ const name = normalizePackageName(item.package.name)
83
+ const market = marketIndex()[name]
84
+ const version = item.package.version || ''
85
+ const displayName = shortname(name)
86
+ return {
87
+ name,
88
+ shortname: displayName,
89
+ version,
90
+ label: `${displayName} · ${name}@${version}`,
91
+ description: pickDescription(market?.manifest?.description)
92
+ || pickDescription(item.package.description)
93
+ || '没有本地描述。',
94
+ hasSchema: !!item.runtime?.schema,
95
+ added: members.some(member => member.package === name),
96
+ verified: !!market?.verified,
97
+ insecure: !!market?.insecure,
98
+ deprecated: !!market?.deprecated,
99
+ category: market?.category,
100
+ }
101
+ })
102
+ .sort((a, b) => a.shortname.localeCompare(b.shortname))
60
103
  })
61
104
 
62
105
  function packageInfo(name: string): any {
@@ -79,12 +122,12 @@ export function useBundleDraft() {
79
122
  return [...collectSensitiveKeys(member.configObject)].slice(0, 8)
80
123
  }
81
124
 
82
- function addMember(name: string, version?: string) {
125
+ function addMember(name: string, version?: string, silent = false) {
83
126
  const packageName = normalizePackageName(name)
84
- if (!packageName) return
127
+ if (!packageName) return false
85
128
  if (members.some(member => member.package === packageName)) {
86
- message.warning('这个成员已经在列表中。')
87
- return
129
+ if (!silent) message.warning('这个成员已经在列表中。')
130
+ return false
88
131
  }
89
132
  members.push({
90
133
  id: createId(),
@@ -96,6 +139,18 @@ export function useBundleDraft() {
96
139
  configObject: {},
97
140
  autoPlugin: true,
98
141
  })
142
+ return true
143
+ }
144
+
145
+ function addMembers(names: string[]) {
146
+ let added = 0
147
+ let skipped = 0
148
+ for (const name of [...new Set(names.map(normalizePackageName).filter(Boolean))]) {
149
+ if (addMember(name, undefined, true)) added += 1
150
+ else skipped += 1
151
+ }
152
+ if (added) message.success(`已加入 ${added} 个成员。`)
153
+ else if (skipped) message.warning('选择的插件都已经在成员列表中。')
99
154
  }
100
155
 
101
156
  function removeMember(index: number) {
@@ -210,6 +265,7 @@ export function useBundleDraft() {
210
265
  hasPresetConfig,
211
266
  sensitiveKeys,
212
267
  addMember,
268
+ addMembers,
213
269
  removeMember,
214
270
  moveMember,
215
271
  syncPluginKey,
@@ -7,26 +7,58 @@
7
7
  </div>
8
8
  </div>
9
9
 
10
- <div class="bw-add-grid">
11
- <div class="bw-add-source">
12
- <span class="bw-add-label is-muted">已安装</span>
13
- <el-select
14
- v-model="selectedInstalled"
15
- filterable
10
+ <div class="bw-installed-picker">
11
+ <div class="bw-installed-toolbar">
12
+ <div>
13
+ <span class="bw-add-label">已安装插件</span>
14
+ <span class="is-muted">已选 {{ selectedInstalled.length }} / 可选 {{ availableInstalledCount }}</span>
15
+ </div>
16
+ <el-input
17
+ v-model="installedKeyword"
16
18
  clearable
17
- :disabled="!api.installedOptions.value.length"
18
- :placeholder="api.installedOptions.value.length ? '选择已安装插件' : '没有可选的已安装插件'"
19
+ class="bw-installed-search"
20
+ placeholder="搜索插件名、包名、描述或版本"
21
+ ></el-input>
22
+ <div class="bw-installed-actions">
23
+ <el-button size="small" :disabled="!filteredSelectable.length" @click="selectFiltered">全选当前</el-button>
24
+ <el-button size="small" :disabled="!selectedInstalled.length" @click="clearInstalledSelection">清空</el-button>
25
+ <el-button type="primary" size="small" :disabled="!selectedInstalled.length" @click="addInstalled">
26
+ 加入已选
27
+ </el-button>
28
+ </div>
29
+ </div>
30
+
31
+ <div v-if="filteredInstalled.length" class="bw-installed-grid">
32
+ <button
33
+ v-for="item in filteredInstalled"
34
+ :key="item.name"
35
+ type="button"
36
+ :class="['bw-installed-card', { selected: selectedInstalledSet.has(item.name), added: item.added, danger: item.insecure || item.deprecated }]"
37
+ :disabled="item.added"
38
+ @click="toggleInstalled(item.name)"
19
39
  >
20
- <el-option
21
- v-for="item in api.installedOptions.value"
22
- :key="item.name"
23
- :value="item.name"
24
- :label="item.label"
25
- ></el-option>
26
- </el-select>
27
- <el-button type="primary" :disabled="!selectedInstalled" @click="addInstalled">加入</el-button>
40
+ <span class="bw-installed-check">{{ item.added ? '已加入' : selectedInstalledSet.has(item.name) ? '已选' : '可选' }}</span>
41
+ <span class="bw-installed-main">
42
+ <strong>{{ item.shortname }}</strong>
43
+ <span class="bw-installed-package" :title="item.name">{{ item.name }}</span>
44
+ <span class="bw-installed-desc" :title="item.description">{{ item.description }}</span>
45
+ </span>
46
+ <span class="bw-installed-meta">
47
+ <span>{{ item.version }}</span>
48
+ <span v-if="item.hasSchema">schema</span>
49
+ <span v-if="item.verified" class="ok">市场认证</span>
50
+ <span v-if="item.insecure" class="danger">风险</span>
51
+ <span v-if="item.deprecated" class="danger">废弃</span>
52
+ </span>
53
+ </button>
28
54
  </div>
29
55
 
56
+ <div v-else class="bw-empty compact">
57
+ {{ api.installedOptions.value.length ? '没有匹配的已安装插件。' : '没有可选的已安装插件。' }}
58
+ </div>
59
+ </div>
60
+
61
+ <div class="bw-add-grid">
30
62
  <div class="bw-add-source">
31
63
  <span class="bw-add-label is-muted">手动添加</span>
32
64
  <el-input
@@ -81,16 +113,39 @@
81
113
  </template>
82
114
 
83
115
  <script lang="ts" setup>
84
- import { ref } from 'vue'
116
+ import { computed, ref, watch } from 'vue'
85
117
  import MemberRow from '../components/MemberRow.vue'
86
118
  import type { BundleDraftApi, MemberView } from '../composables/useBundleDraft'
87
119
 
88
120
  const props = defineProps<{ api: BundleDraftApi }>()
89
121
 
90
- const selectedInstalled = ref('')
122
+ const selectedInstalled = ref<string[]>([])
123
+ const installedKeyword = ref('')
91
124
  const manualName = ref('')
92
125
  const expanded = ref<Set<string>>(new Set())
93
126
 
127
+ const selectedInstalledSet = computed(() => new Set(selectedInstalled.value))
128
+ const availableInstalledCount = computed(() => props.api.installedOptions.value.filter(item => !item.added).length)
129
+ const filteredInstalled = computed(() => {
130
+ const word = installedKeyword.value.trim().toLowerCase()
131
+ return props.api.installedOptions.value.filter((item) => {
132
+ if (!word) return true
133
+ return [
134
+ item.name,
135
+ item.shortname,
136
+ item.version,
137
+ item.description,
138
+ item.category,
139
+ ].some(value => String(value ?? '').toLowerCase().includes(word))
140
+ })
141
+ })
142
+ const filteredSelectable = computed(() => filteredInstalled.value.filter(item => !item.added))
143
+
144
+ watch(() => props.api.installedOptions.value, (options) => {
145
+ const available = new Set(options.filter(item => !item.added).map(item => item.name))
146
+ selectedInstalled.value = selectedInstalled.value.filter(name => available.has(name))
147
+ }, { deep: true })
148
+
94
149
  function toggleExpanded(id: string) {
95
150
  const next = new Set(expanded.value)
96
151
  if (next.has(id)) next.delete(id)
@@ -99,9 +154,28 @@ function toggleExpanded(id: string) {
99
154
  }
100
155
 
101
156
  function addInstalled() {
102
- if (!selectedInstalled.value) return
103
- props.api.addMember(selectedInstalled.value)
104
- selectedInstalled.value = ''
157
+ if (!selectedInstalled.value.length) return
158
+ props.api.addMembers(selectedInstalled.value)
159
+ selectedInstalled.value = []
160
+ }
161
+
162
+ function toggleInstalled(name: string) {
163
+ const item = props.api.installedOptions.value.find(item => item.name === name)
164
+ if (!item || item.added) return
165
+ const next = new Set(selectedInstalled.value)
166
+ if (next.has(name)) next.delete(name)
167
+ else next.add(name)
168
+ selectedInstalled.value = [...next]
169
+ }
170
+
171
+ function selectFiltered() {
172
+ const next = new Set(selectedInstalled.value)
173
+ for (const item of filteredSelectable.value) next.add(item.name)
174
+ selectedInstalled.value = [...next]
175
+ }
176
+
177
+ function clearInstalledSelection() {
178
+ selectedInstalled.value = []
105
179
  }
106
180
 
107
181
  function addManual() {
@@ -120,9 +194,164 @@ function onPackageChange(member: MemberView, value: string) {
120
194
  margin-bottom: var(--bw-gap-md);
121
195
  }
122
196
 
197
+ .bw-installed-picker {
198
+ display: grid;
199
+ gap: var(--bw-gap-sm);
200
+ margin-bottom: var(--bw-gap-md);
201
+ }
202
+
203
+ .bw-installed-toolbar {
204
+ display: grid;
205
+ grid-template-columns: auto minmax(16rem, 1fr) auto;
206
+ align-items: center;
207
+ gap: var(--bw-gap-sm);
208
+
209
+ > div:first-child {
210
+ display: grid;
211
+ gap: 0.08rem;
212
+ }
213
+ }
214
+
215
+ .bw-installed-search {
216
+ min-width: 0;
217
+ }
218
+
219
+ .bw-installed-actions {
220
+ display: flex;
221
+ align-items: center;
222
+ gap: var(--bw-gap-xs);
223
+ }
224
+
225
+ .bw-installed-grid {
226
+ display: grid;
227
+ grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr));
228
+ gap: var(--bw-gap-sm);
229
+ max-height: 20rem;
230
+ overflow: auto;
231
+ padding: 2px;
232
+ }
233
+
234
+ .bw-installed-card {
235
+ appearance: none;
236
+ display: grid;
237
+ grid-template-columns: auto minmax(0, 1fr);
238
+ gap: 0.42rem 0.58rem;
239
+ align-items: start;
240
+ min-width: 0;
241
+ border: var(--bw-border);
242
+ border-radius: var(--bw-radius-sm);
243
+ padding: 0.54rem 0.62rem;
244
+ color: var(--fg1);
245
+ background: var(--k-card-bg);
246
+ text-align: left;
247
+ cursor: pointer;
248
+ transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
249
+
250
+ &:hover,
251
+ &:focus-visible {
252
+ border-color: color-mix(in srgb, var(--k-color-primary) 42%, var(--k-color-border));
253
+ outline: none;
254
+ }
255
+
256
+ &.selected {
257
+ border-color: color-mix(in srgb, var(--k-color-primary) 62%, var(--k-color-border));
258
+ background:
259
+ linear-gradient(90deg, color-mix(in srgb, var(--k-color-primary) 10%, transparent), transparent 55%),
260
+ var(--k-card-bg);
261
+ box-shadow: inset 3px 0 0 var(--k-color-primary);
262
+ }
263
+
264
+ &.danger {
265
+ border-color: color-mix(in srgb, var(--k-color-danger) 32%, var(--k-color-border));
266
+ }
267
+
268
+ &.added {
269
+ cursor: default;
270
+ opacity: 0.58;
271
+ background: color-mix(in srgb, var(--k-side-bg) 72%, transparent);
272
+ }
273
+ }
274
+
275
+ .bw-installed-check {
276
+ grid-row: 1 / span 2;
277
+ display: inline-flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ min-width: 2.6rem;
281
+ height: 1.35rem;
282
+ border-radius: 999px;
283
+ color: var(--fg2);
284
+ background: color-mix(in srgb, var(--fg3) 10%, transparent);
285
+ font-size: 0.72rem;
286
+ font-weight: 600;
287
+
288
+ .bw-installed-card.selected & {
289
+ color: var(--k-color-primary);
290
+ background: color-mix(in srgb, var(--k-color-primary) 12%, transparent);
291
+ }
292
+ }
293
+
294
+ .bw-installed-main {
295
+ min-width: 0;
296
+ display: grid;
297
+ gap: 0.12rem;
298
+
299
+ strong {
300
+ min-width: 0;
301
+ overflow: hidden;
302
+ text-overflow: ellipsis;
303
+ white-space: nowrap;
304
+ font-size: 0.88rem;
305
+ }
306
+ }
307
+
308
+ .bw-installed-package,
309
+ .bw-installed-desc {
310
+ min-width: 0;
311
+ overflow: hidden;
312
+ text-overflow: ellipsis;
313
+ white-space: nowrap;
314
+ }
315
+
316
+ .bw-installed-package {
317
+ color: var(--fg3);
318
+ font-family: var(--bw-font-mono);
319
+ font-size: 0.72rem;
320
+ }
321
+
322
+ .bw-installed-desc {
323
+ color: var(--fg2);
324
+ font-size: 0.75rem;
325
+ }
326
+
327
+ .bw-installed-meta {
328
+ grid-column: 2;
329
+ display: flex;
330
+ flex-wrap: wrap;
331
+ gap: 0.24rem;
332
+
333
+ span {
334
+ border-radius: 4px;
335
+ padding: 0.04rem 0.34rem;
336
+ color: var(--fg3);
337
+ background: color-mix(in srgb, var(--fg3) 9%, transparent);
338
+ font-size: 0.68rem;
339
+
340
+ &.ok {
341
+ color: var(--k-color-success);
342
+ background: color-mix(in srgb, var(--k-color-success) 10%, transparent);
343
+ }
344
+
345
+ &.danger {
346
+ color: var(--k-color-danger);
347
+ background: color-mix(in srgb, var(--k-color-danger) 10%, transparent);
348
+ }
349
+ }
350
+ }
351
+
123
352
  .bw-add-grid {
124
353
  display: grid;
125
- grid-template-columns: repeat(2, minmax(0, 1fr));
354
+ grid-template-columns: minmax(0, 1fr);
126
355
  gap: var(--bw-gap-md);
127
356
  }
128
357
 
@@ -139,8 +368,19 @@ function onPackageChange(member: MemberView, value: string) {
139
368
  }
140
369
 
141
370
  @media (max-width: 820px) {
142
- .bw-add-grid {
371
+ .bw-installed-toolbar {
372
+ grid-template-columns: 1fr;
373
+ align-items: stretch;
374
+ }
375
+
376
+ .bw-installed-actions {
377
+ justify-content: flex-end;
378
+ flex-wrap: wrap;
379
+ }
380
+
381
+ .bw-installed-grid {
143
382
  grid-template-columns: 1fr;
383
+ max-height: 18rem;
144
384
  }
145
385
 
146
386
  .bw-add-source {
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.bw-step-indicator{display:flex;align-items:center;gap:0;margin:0;padding:0;list-style:none;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}.bw-step{display:flex;align-items:center;flex:0 0 auto}.bw-step:last-child{flex:0 1 auto}.bw-step-btn{display:inline-flex;align-items:center;gap:.45rem;border:0;background:transparent;padding:.3rem .5rem;color:var(--fg2);font-size:.86rem;cursor:pointer;border-radius:var(--bw-radius-sm)}.bw-step-btn:hover{color:var(--fg1);background:color-mix(in srgb,var(--k-color-primary) 6%,transparent)}.bw-step-mark{display:inline-grid;place-items:center;width:var(--bw-step-size);height:var(--bw-step-size);border-radius:999px;border:1px solid var(--fg3);color:var(--fg3);font-size:.78rem;font-weight:600;background:var(--k-card-bg)}.bw-step-label{font-weight:500}.bw-step-rule{display:inline-block;width:1.6rem;height:1px;margin:0 .25rem;background:var(--fg3);opacity:.6}.bw-step.current .bw-step-mark{border-color:var(--k-color-primary);color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 10%,var(--k-card-bg))}.bw-step.current .bw-step-label{color:var(--fg1);font-weight:600}.bw-step.done .bw-step-mark{border-color:var(--k-color-success);color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,var(--k-card-bg))}.bw-step.done .bw-step-label{color:var(--fg1)}.bw-step.error .bw-step-mark{border-color:var(--k-color-danger);color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,var(--k-card-bg))}.bw-step.error .bw-step-label{color:var(--k-color-danger)}@media (max-width: 720px){.bw-step-rule{width:.8rem}.bw-step-btn{padding:.2rem .35rem;font-size:.8rem}}.bw-header{flex:0 0 auto;padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-bottom:var(--bw-border)}.bw-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-lg);flex-wrap:wrap}.bw-header-title{min-width:0}.bw-header-title h1{margin:0;font-size:1.05rem;font-weight:600;color:var(--fg1)}.bw-header-title p{margin:.2rem 0 0;color:var(--fg3);font-size:.82rem;line-height:1.5;max-width:48rem}.bw-header-meta{font-size:.8rem}.bw-pkg-name{font-family:var(--bw-font-mono);color:var(--fg1);font-weight:500}.bw-header-rule{height:var(--bw-gap-md)}@media (max-width: 720px){.bw-header{padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-header-meta{width:100%}}.bw-footer{flex:0 0 auto;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-md);padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-top:var(--bw-border)}.bw-footer-hint{font-size:.85rem;text-align:center;min-width:0}.bw-footer-hint span{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.bw-footer-right{display:flex;justify-content:flex-end;gap:var(--bw-gap-sm)}@media (max-width: 720px){.bw-footer{grid-template-columns:1fr 1fr;grid-template-areas:"hint hint" "left right";padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-footer-hint{grid-area:hint;text-align:left}.bw-footer-left{grid-area:left}.bw-footer-right{grid-area:right}}.bw-form-error{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-error code{font-family:var(--bw-font-mono)}.bw-form-note{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-note code{font-family:var(--bw-font-mono)}.bw-member-row{display:contents}.bw-row-main{grid-template-columns:minmax(13rem,2.4fr) minmax(7rem,1fr) 7rem minmax(8rem,1.4fr) auto}.bw-row-main>div{min-width:0}.bw-cell-name{display:flex;align-items:center;gap:var(--bw-gap-sm);min-width:0}.bw-expander{flex:0 0 auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--fg3);font-size:.85rem;cursor:pointer;padding:0 .25rem;width:1.4rem}.bw-name-block{min-width:0;display:flex;flex-direction:column;gap:.1rem;overflow:hidden}.bw-name-block strong{color:var(--fg1);font-size:.9rem;font-weight:600}.bw-name-block span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;font-family:var(--bw-font-mono)}.bw-cell-status{font-size:.76rem;gap:var(--bw-gap-xs) var(--bw-gap-sm)}.bw-cell-actions{display:flex;gap:.15rem;white-space:nowrap}.bw-row-detail{background:var(--bw-bg-elev)}.bw-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-detail-grid label{display:grid;gap:.25rem}.bw-detail-grid label>span{color:var(--fg3);font-size:.78rem}@media (max-width: 820px){.bw-row-main{grid-template-columns:1fr auto;grid-template-areas:"name actions" "version type" "status status";row-gap:var(--bw-gap-xs)}.bw-cell-name{grid-area:name}.bw-cell-version{grid-area:version}.bw-cell-type{grid-area:type}.bw-cell-status{grid-area:status}.bw-cell-actions{grid-area:actions}.bw-detail-grid{grid-template-columns:1fr}}.bw-add-card{margin-bottom:var(--bw-gap-md)}.bw-add-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-add-source{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-add-label{font-size:.82rem;white-space:nowrap}@media (max-width: 820px){.bw-add-grid{grid-template-columns:1fr}.bw-add-source{grid-template-columns:minmax(0,1fr) auto}.bw-add-source .bw-add-label{grid-column:1/-1}.bw-row-main.bw-th{display:none}}.bw-config-editor+.bw-config-editor{margin-top:var(--bw-gap-md)}.bw-sensitive{display:flex;align-items:center;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md);padding:.45rem var(--bw-gap-md);border-radius:var(--bw-radius-sm);background:color-mix(in srgb,var(--k-color-warning) 8%,transparent);font-size:.82rem}.bw-sensitive strong{flex:0 0 auto}.bw-sensitive span{word-break:break-all}.bw-tab-body{display:grid;gap:var(--bw-gap-sm)}.bw-tab-actions{display:flex;align-items:center;gap:var(--bw-gap-sm);font-size:.82rem}.bw-validate-grid{display:grid;gap:var(--bw-gap-md)}.bw-validate-summary{display:flex;justify-content:space-between;gap:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-validate-summary strong{font-size:1rem}.bw-validate-summary span{font-size:.85rem}.bw-validate-npm,.bw-validate-issues{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-md)}.bw-validate-npm h3,.bw-validate-issues h3{margin:0 0 var(--bw-gap-sm);font-size:.88rem;color:var(--fg2)}.bw-validate-npm-item{display:flex;align-items:center;justify-content:space-between;gap:var(--bw-gap-md);padding:.35rem 0;border-bottom:var(--bw-border-soft)}.bw-validate-npm-item:last-child{border-bottom:0}.bw-validate-npm-item strong{font-family:var(--bw-font-mono);font-size:.85rem}.bw-validate-npm-item span{display:block;font-size:.78rem}.bw-issue{display:grid;grid-template-columns:4.5rem minmax(0,1fr);gap:var(--bw-gap-sm);padding:.3rem 0;font-size:.84rem;color:var(--fg2)}.bw-issue strong{text-transform:uppercase;font-size:.74rem;letter-spacing:.04em;align-self:center}.bw-issue.error strong,.bw-issue.error span{color:var(--k-color-danger)}.bw-issue.warning strong{color:var(--k-color-warning)}.bw-issue-path{font-family:var(--bw-font-mono);font-size:.78rem;color:var(--fg3);margin-right:.25rem}.bw-result-panel{display:grid;gap:var(--bw-gap-sm);margin-top:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-result-head{display:flex;align-items:baseline;gap:var(--bw-gap-md);flex-wrap:wrap}.bw-result-head strong{font-size:.94rem}.bw-result-head span{font-size:.82rem}.bw-download-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-download-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;gap:var(--bw-gap-xs);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--k-card-bg);cursor:pointer;text-align:left}.bw-download-card:hover:not(:disabled){border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-card:disabled{cursor:progress;opacity:.7}.bw-download-card.primary{border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-title{color:var(--fg1);font-size:.95rem;font-weight:600}.bw-download-desc{font-size:.8rem;line-height:1.5}.bw-download-busy{font-size:.78rem;margin-top:.2rem}.bw-write-controls{margin-top:var(--bw-gap-md);font-size:.85rem}.bw-write-controls .bw-toolbar-spacer{flex:1}.bw-checkbox-line{display:inline-flex;align-items:center;gap:.35rem}.bw-issue-warnings{display:grid;gap:.2rem}.bw-issue-warnings p{margin:0;font-size:.82rem}.bw-file-list{display:grid;gap:.2rem}.bw-file-list p{display:flex;justify-content:space-between;gap:var(--bw-gap-md);margin:0;font-size:.82rem;color:var(--fg2)}.bw-file-list code{font-family:var(--bw-font-mono)}.bw-pack-files{margin:.2rem 0 0;padding-left:1.2rem;font-size:.82rem;color:var(--fg2)}.bw-pack-files li{line-height:1.5}.bw-pack-files code{font-family:var(--bw-font-mono)}.bw-output-tabs{margin-top:var(--bw-gap-md)}@media (max-width: 720px){.bw-download-grid{grid-template-columns:1fr}}:root{--bw-gap-xs: .35rem;--bw-gap-sm: .5rem;--bw-gap-md: .75rem;--bw-gap-lg: 1rem;--bw-gap-xl: 1.4rem;--bw-radius: 6px;--bw-radius-sm: 4px;--bw-border: 1px solid color-mix(in srgb, var(--k-color-border) 70%, transparent);--bw-border-strong: 1px solid color-mix(in srgb, var(--k-color-border) 95%, transparent);--bw-border-soft: 1px solid color-mix(in srgb, var(--k-color-border) 45%, transparent);--bw-bg-soft: color-mix(in srgb, var(--k-card-bg) 88%, transparent);--bw-bg-elev: color-mix(in srgb, var(--k-side-bg) 60%, var(--k-card-bg));--bw-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bw-step-size: 1.4rem}.bw-shell{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;overflow:hidden;background:var(--k-side-bg)}.bw-shell code{font-family:var(--bw-font-mono)}.bw-main{flex:1 1 auto;min-height:0;overflow:auto;padding:var(--bw-gap-lg)}.bw-card{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-lg);background:var(--k-card-bg)}.bw-card+.bw-card{margin-top:var(--bw-gap-md)}.bw-card h2,.bw-card h3{margin:0;font-size:1rem}.bw-card>.bw-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-md);margin-bottom:var(--bw-gap-md)}.bw-card>.bw-card-head h2{font-size:1rem}.bw-card>.bw-card-head p{margin:.2rem 0 0;color:var(--fg3);font-size:.84rem;line-height:1.55}.bw-toolbar{display:flex;align-items:center;gap:var(--bw-gap-sm);flex-wrap:wrap}.bw-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-form-grid label{display:grid;gap:.32rem}.bw-form-grid label>span{color:var(--fg2);font-size:.82rem}.bw-form-grid .bw-span-2{grid-column:1/-1}.bw-status-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--bw-gap-xs) var(--bw-gap-md);color:var(--fg3);font-size:.8rem}.bw-status-line span.dot:before{content:"·";margin:0 .25rem}.is-ok{color:var(--k-color-success)!important}.is-warn{color:var(--k-color-warning)!important}.is-danger{color:var(--k-color-danger)!important}.is-muted{color:var(--fg3)!important}.is-accent{color:var(--k-color-primary)!important}.bw-table{display:grid;width:100%;border:var(--bw-border);border-radius:var(--bw-radius);overflow:hidden;background:var(--k-card-bg)}.bw-table .bw-tr{display:grid;align-items:center;gap:var(--bw-gap-sm);padding:.45rem var(--bw-gap-md);border-top:var(--bw-border-soft)}.bw-table .bw-tr:first-child{border-top:0}.bw-table .bw-tr.bw-th{background:var(--bw-bg-elev);color:var(--fg3);font-size:.78rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.bw-table .bw-tr.bw-row-detail{grid-template-columns:1fr;padding:var(--bw-gap-md);background:var(--bw-bg-elev);border-top:var(--bw-border-soft)}.bw-tabs{display:flex;gap:0;border-bottom:var(--bw-border-soft);margin-bottom:var(--bw-gap-md)}.bw-tabs button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;padding:.45rem .85rem;color:var(--fg2);font-size:.85rem;cursor:pointer;border-bottom:2px solid transparent}.bw-tabs button:hover{color:var(--fg1)}.bw-tabs button.active{color:var(--fg1);border-bottom-color:var(--k-color-primary)}.bw-tabs button:disabled{color:var(--fg3);cursor:not-allowed}.bw-empty{display:grid;place-items:center;gap:var(--bw-gap-xs);padding:var(--bw-gap-xl) var(--bw-gap-md);color:var(--fg3);text-align:center;font-size:.88rem}.bw-pre{max-height:28rem;margin:0;border-radius:var(--bw-radius-sm);padding:var(--bw-gap-md);overflow:auto;background:var(--k-color-code-bg, rgba(0, 0, 0, .08));font-family:var(--bw-font-mono);font-size:.78rem;line-height:1.5}@media (max-width: 720px){.bw-form-grid{grid-template-columns:1fr}}.bundle-workbench{display:flex;min-height:0;overflow:hidden}
1
+ @charset "UTF-8";.bw-step-indicator{display:flex;align-items:center;gap:0;margin:0;padding:0;list-style:none;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}.bw-step{display:flex;align-items:center;flex:0 0 auto}.bw-step:last-child{flex:0 1 auto}.bw-step-btn{display:inline-flex;align-items:center;gap:.45rem;border:0;background:transparent;padding:.3rem .5rem;color:var(--fg2);font-size:.86rem;cursor:pointer;border-radius:var(--bw-radius-sm)}.bw-step-btn:hover{color:var(--fg1);background:color-mix(in srgb,var(--k-color-primary) 6%,transparent)}.bw-step-mark{display:inline-grid;place-items:center;width:var(--bw-step-size);height:var(--bw-step-size);border-radius:999px;border:1px solid var(--fg3);color:var(--fg3);font-size:.78rem;font-weight:600;background:var(--k-card-bg)}.bw-step-label{font-weight:500}.bw-step-rule{display:inline-block;width:1.6rem;height:1px;margin:0 .25rem;background:var(--fg3);opacity:.6}.bw-step.current .bw-step-mark{border-color:var(--k-color-primary);color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 10%,var(--k-card-bg))}.bw-step.current .bw-step-label{color:var(--fg1);font-weight:600}.bw-step.done .bw-step-mark{border-color:var(--k-color-success);color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,var(--k-card-bg))}.bw-step.done .bw-step-label{color:var(--fg1)}.bw-step.error .bw-step-mark{border-color:var(--k-color-danger);color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,var(--k-card-bg))}.bw-step.error .bw-step-label{color:var(--k-color-danger)}@media (max-width: 720px){.bw-step-rule{width:.8rem}.bw-step-btn{padding:.2rem .35rem;font-size:.8rem}}.bw-header{flex:0 0 auto;padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-bottom:var(--bw-border)}.bw-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-lg);flex-wrap:wrap}.bw-header-title{min-width:0}.bw-header-title h1{margin:0;font-size:1.05rem;font-weight:600;color:var(--fg1)}.bw-header-title p{margin:.2rem 0 0;color:var(--fg3);font-size:.82rem;line-height:1.5;max-width:48rem}.bw-header-meta{font-size:.8rem}.bw-pkg-name{font-family:var(--bw-font-mono);color:var(--fg1);font-weight:500}.bw-header-rule{height:var(--bw-gap-md)}@media (max-width: 720px){.bw-header{padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-header-meta{width:100%}}.bw-footer{flex:0 0 auto;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-md);padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-top:var(--bw-border)}.bw-footer-hint{font-size:.85rem;text-align:center;min-width:0}.bw-footer-hint span{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.bw-footer-right{display:flex;justify-content:flex-end;gap:var(--bw-gap-sm)}@media (max-width: 720px){.bw-footer{grid-template-columns:1fr 1fr;grid-template-areas:"hint hint" "left right";padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-footer-hint{grid-area:hint;text-align:left}.bw-footer-left{grid-area:left}.bw-footer-right{grid-area:right}}.bw-form-error{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-error code{font-family:var(--bw-font-mono)}.bw-form-note{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-note code{font-family:var(--bw-font-mono)}.bw-member-row{display:contents}.bw-row-main{grid-template-columns:minmax(13rem,2.4fr) minmax(7rem,1fr) 7rem minmax(8rem,1.4fr) auto}.bw-row-main>div{min-width:0}.bw-cell-name{display:flex;align-items:center;gap:var(--bw-gap-sm);min-width:0}.bw-expander{flex:0 0 auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--fg3);font-size:.85rem;cursor:pointer;padding:0 .25rem;width:1.4rem}.bw-name-block{min-width:0;display:flex;flex-direction:column;gap:.1rem;overflow:hidden}.bw-name-block strong{color:var(--fg1);font-size:.9rem;font-weight:600}.bw-name-block span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;font-family:var(--bw-font-mono)}.bw-cell-status{font-size:.76rem;gap:var(--bw-gap-xs) var(--bw-gap-sm)}.bw-cell-actions{display:flex;gap:.15rem;white-space:nowrap}.bw-row-detail{background:var(--bw-bg-elev)}.bw-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-detail-grid label{display:grid;gap:.25rem}.bw-detail-grid label>span{color:var(--fg3);font-size:.78rem}@media (max-width: 820px){.bw-row-main{grid-template-columns:1fr auto;grid-template-areas:"name actions" "version type" "status status";row-gap:var(--bw-gap-xs)}.bw-cell-name{grid-area:name}.bw-cell-version{grid-area:version}.bw-cell-type{grid-area:type}.bw-cell-status{grid-area:status}.bw-cell-actions{grid-area:actions}.bw-detail-grid{grid-template-columns:1fr}}.bw-add-card{margin-bottom:var(--bw-gap-md)}.bw-installed-picker{display:grid;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md)}.bw-installed-toolbar{display:grid;grid-template-columns:auto minmax(16rem,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-installed-toolbar>div:first-child{display:grid;gap:.08rem}.bw-installed-search{min-width:0}.bw-installed-actions{display:flex;align-items:center;gap:var(--bw-gap-xs)}.bw-installed-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(16.5rem,1fr));gap:var(--bw-gap-sm);max-height:20rem;overflow:auto;padding:2px}.bw-installed-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;grid-template-columns:auto minmax(0,1fr);gap:.42rem .58rem;align-items:start;min-width:0;border:var(--bw-border);border-radius:var(--bw-radius-sm);padding:.54rem .62rem;color:var(--fg1);background:var(--k-card-bg);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,box-shadow .15s}.bw-installed-card:hover,.bw-installed-card:focus-visible{border-color:color-mix(in srgb,var(--k-color-primary) 42%,var(--k-color-border));outline:none}.bw-installed-card.selected{border-color:color-mix(in srgb,var(--k-color-primary) 62%,var(--k-color-border));background:linear-gradient(90deg,color-mix(in srgb,var(--k-color-primary) 10%,transparent),transparent 55%),var(--k-card-bg);box-shadow:inset 3px 0 0 var(--k-color-primary)}.bw-installed-card.danger{border-color:color-mix(in srgb,var(--k-color-danger) 32%,var(--k-color-border))}.bw-installed-card.added{cursor:default;opacity:.58;background:color-mix(in srgb,var(--k-side-bg) 72%,transparent)}.bw-installed-check{grid-row:1/span 2;display:inline-flex;align-items:center;justify-content:center;min-width:2.6rem;height:1.35rem;border-radius:999px;color:var(--fg2);background:color-mix(in srgb,var(--fg3) 10%,transparent);font-size:.72rem;font-weight:600}.bw-installed-card.selected .bw-installed-check{color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 12%,transparent)}.bw-installed-main{min-width:0;display:grid;gap:.12rem}.bw-installed-main strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.88rem}.bw-installed-package,.bw-installed-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bw-installed-package{color:var(--fg3);font-family:var(--bw-font-mono);font-size:.72rem}.bw-installed-desc{color:var(--fg2);font-size:.75rem}.bw-installed-meta{grid-column:2;display:flex;flex-wrap:wrap;gap:.24rem}.bw-installed-meta span{border-radius:4px;padding:.04rem .34rem;color:var(--fg3);background:color-mix(in srgb,var(--fg3) 9%,transparent);font-size:.68rem}.bw-installed-meta span.ok{color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,transparent)}.bw-installed-meta span.danger{color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,transparent)}.bw-add-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--bw-gap-md)}.bw-add-source{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-add-label{font-size:.82rem;white-space:nowrap}@media (max-width: 820px){.bw-installed-toolbar{grid-template-columns:1fr;align-items:stretch}.bw-installed-actions{justify-content:flex-end;flex-wrap:wrap}.bw-installed-grid{grid-template-columns:1fr;max-height:18rem}.bw-add-source{grid-template-columns:minmax(0,1fr) auto}.bw-add-source .bw-add-label{grid-column:1/-1}.bw-row-main.bw-th{display:none}}.bw-config-editor+.bw-config-editor{margin-top:var(--bw-gap-md)}.bw-sensitive{display:flex;align-items:center;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md);padding:.45rem var(--bw-gap-md);border-radius:var(--bw-radius-sm);background:color-mix(in srgb,var(--k-color-warning) 8%,transparent);font-size:.82rem}.bw-sensitive strong{flex:0 0 auto}.bw-sensitive span{word-break:break-all}.bw-tab-body{display:grid;gap:var(--bw-gap-sm)}.bw-tab-actions{display:flex;align-items:center;gap:var(--bw-gap-sm);font-size:.82rem}.bw-validate-grid{display:grid;gap:var(--bw-gap-md)}.bw-validate-summary{display:flex;justify-content:space-between;gap:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-validate-summary strong{font-size:1rem}.bw-validate-summary span{font-size:.85rem}.bw-validate-npm,.bw-validate-issues{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-md)}.bw-validate-npm h3,.bw-validate-issues h3{margin:0 0 var(--bw-gap-sm);font-size:.88rem;color:var(--fg2)}.bw-validate-npm-item{display:flex;align-items:center;justify-content:space-between;gap:var(--bw-gap-md);padding:.35rem 0;border-bottom:var(--bw-border-soft)}.bw-validate-npm-item:last-child{border-bottom:0}.bw-validate-npm-item strong{font-family:var(--bw-font-mono);font-size:.85rem}.bw-validate-npm-item span{display:block;font-size:.78rem}.bw-issue{display:grid;grid-template-columns:4.5rem minmax(0,1fr);gap:var(--bw-gap-sm);padding:.3rem 0;font-size:.84rem;color:var(--fg2)}.bw-issue strong{text-transform:uppercase;font-size:.74rem;letter-spacing:.04em;align-self:center}.bw-issue.error strong,.bw-issue.error span{color:var(--k-color-danger)}.bw-issue.warning strong{color:var(--k-color-warning)}.bw-issue-path{font-family:var(--bw-font-mono);font-size:.78rem;color:var(--fg3);margin-right:.25rem}.bw-result-panel{display:grid;gap:var(--bw-gap-sm);margin-top:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-result-head{display:flex;align-items:baseline;gap:var(--bw-gap-md);flex-wrap:wrap}.bw-result-head strong{font-size:.94rem}.bw-result-head span{font-size:.82rem}.bw-download-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-download-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;gap:var(--bw-gap-xs);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--k-card-bg);cursor:pointer;text-align:left}.bw-download-card:hover:not(:disabled){border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-card:disabled{cursor:progress;opacity:.7}.bw-download-card.primary{border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-title{color:var(--fg1);font-size:.95rem;font-weight:600}.bw-download-desc{font-size:.8rem;line-height:1.5}.bw-download-busy{font-size:.78rem;margin-top:.2rem}.bw-write-controls{margin-top:var(--bw-gap-md);font-size:.85rem}.bw-write-controls .bw-toolbar-spacer{flex:1}.bw-checkbox-line{display:inline-flex;align-items:center;gap:.35rem}.bw-issue-warnings{display:grid;gap:.2rem}.bw-issue-warnings p{margin:0;font-size:.82rem}.bw-file-list{display:grid;gap:.2rem}.bw-file-list p{display:flex;justify-content:space-between;gap:var(--bw-gap-md);margin:0;font-size:.82rem;color:var(--fg2)}.bw-file-list code{font-family:var(--bw-font-mono)}.bw-pack-files{margin:.2rem 0 0;padding-left:1.2rem;font-size:.82rem;color:var(--fg2)}.bw-pack-files li{line-height:1.5}.bw-pack-files code{font-family:var(--bw-font-mono)}.bw-output-tabs{margin-top:var(--bw-gap-md)}@media (max-width: 720px){.bw-download-grid{grid-template-columns:1fr}}:root{--bw-gap-xs: .35rem;--bw-gap-sm: .5rem;--bw-gap-md: .75rem;--bw-gap-lg: 1rem;--bw-gap-xl: 1.4rem;--bw-radius: 6px;--bw-radius-sm: 4px;--bw-border: 1px solid color-mix(in srgb, var(--k-color-border) 70%, transparent);--bw-border-strong: 1px solid color-mix(in srgb, var(--k-color-border) 95%, transparent);--bw-border-soft: 1px solid color-mix(in srgb, var(--k-color-border) 45%, transparent);--bw-bg-soft: color-mix(in srgb, var(--k-card-bg) 88%, transparent);--bw-bg-elev: color-mix(in srgb, var(--k-side-bg) 60%, var(--k-card-bg));--bw-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bw-step-size: 1.4rem}.bw-shell{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;overflow:hidden;background:var(--k-side-bg)}.bw-shell code{font-family:var(--bw-font-mono)}.bw-main{flex:1 1 auto;min-height:0;overflow:auto;padding:var(--bw-gap-lg)}.bw-card{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-lg);background:var(--k-card-bg)}.bw-card+.bw-card{margin-top:var(--bw-gap-md)}.bw-card h2,.bw-card h3{margin:0;font-size:1rem}.bw-card>.bw-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-md);margin-bottom:var(--bw-gap-md)}.bw-card>.bw-card-head h2{font-size:1rem}.bw-card>.bw-card-head p{margin:.2rem 0 0;color:var(--fg3);font-size:.84rem;line-height:1.55}.bw-toolbar{display:flex;align-items:center;gap:var(--bw-gap-sm);flex-wrap:wrap}.bw-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-form-grid label{display:grid;gap:.32rem}.bw-form-grid label>span{color:var(--fg2);font-size:.82rem}.bw-form-grid .bw-span-2{grid-column:1/-1}.bw-status-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--bw-gap-xs) var(--bw-gap-md);color:var(--fg3);font-size:.8rem}.bw-status-line span.dot:before{content:"·";margin:0 .25rem}.is-ok{color:var(--k-color-success)!important}.is-warn{color:var(--k-color-warning)!important}.is-danger{color:var(--k-color-danger)!important}.is-muted{color:var(--fg3)!important}.is-accent{color:var(--k-color-primary)!important}.bw-table{display:grid;width:100%;border:var(--bw-border);border-radius:var(--bw-radius);overflow:hidden;background:var(--k-card-bg)}.bw-table .bw-tr{display:grid;align-items:center;gap:var(--bw-gap-sm);padding:.45rem var(--bw-gap-md);border-top:var(--bw-border-soft)}.bw-table .bw-tr:first-child{border-top:0}.bw-table .bw-tr.bw-th{background:var(--bw-bg-elev);color:var(--fg3);font-size:.78rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.bw-table .bw-tr.bw-row-detail{grid-template-columns:1fr;padding:var(--bw-gap-md);background:var(--bw-bg-elev);border-top:var(--bw-border-soft)}.bw-tabs{display:flex;gap:0;border-bottom:var(--bw-border-soft);margin-bottom:var(--bw-gap-md)}.bw-tabs button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;padding:.45rem .85rem;color:var(--fg2);font-size:.85rem;cursor:pointer;border-bottom:2px solid transparent}.bw-tabs button:hover{color:var(--fg1)}.bw-tabs button.active{color:var(--fg1);border-bottom-color:var(--k-color-primary)}.bw-tabs button:disabled{color:var(--fg3);cursor:not-allowed}.bw-empty{display:grid;place-items:center;gap:var(--bw-gap-xs);padding:var(--bw-gap-xl) var(--bw-gap-md);color:var(--fg3);text-align:center;font-size:.88rem}.bw-pre{max-height:28rem;margin:0;border-radius:var(--bw-radius-sm);padding:var(--bw-gap-md);overflow:auto;background:var(--k-color-code-bg, rgba(0, 0, 0, .08));font-family:var(--bw-font-mono);font-size:.78rem;line-height:1.5}@media (max-width: 720px){.bw-form-grid{grid-template-columns:1fr}}.bundle-workbench{display:flex;min-height:0;overflow:hidden}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import{store as q,message as x,send as F,icons as le}from"@koishijs/client";import{defineComponent as B,openBlock as i,createElementBlock as o,Fragment as K,renderList as I,normalizeClass as M,createElementVNode as t,toDisplayString as v,createCommentVNode as w,createVNode as b,resolveComponent as P,withCtx as C,createTextVNode as $,createBlock as z,computed as N,ref as T,withKeys as se,watch as ie,renderSlot as oe,reactive as Z,unref as h}from"vue";const re={class:"bw-step-indicator",role:"list"},ue=["aria-current","onClick"],de={class:"bw-step-mark"},ce={class:"bw-step-label"},ve={key:0,class:"bw-step-rule","aria-hidden":"true"},me=B({__name:"StepIndicator",props:{steps:{},stepStates:{}},emits:["go"],setup(e){return(s,n)=>(i(),o("ol",re,[(i(true),o(K,null,I(e.steps,(l,a)=>(i(),o("li",{key:l.key,class:M(["bw-step",e.stepStates[l.key]])},[t("button",{type:"button",class:"bw-step-btn","aria-current":e.stepStates[l.key]==="current"?"step":void 0,onClick:p=>s.$emit("go",l.key)},[t("span",de,v(e.stepStates[l.key]==="done"?"✓":a+1),1),t("span",ce,v(l.label),1)],8,ue),a<e.steps.length-1?(i(),o("span",ve)):w("v-if",true)],2))),128))]))}}),be={class:"bw-header"},fe={class:"bw-header-row"},ke={class:"bw-header-title"},ge={class:"bw-header-meta bw-status-line"},pe={class:"dot"},ye={class:"dot"},we={class:"dot"},he={key:0,class:"dot is-danger"},$e={key:1,class:"dot is-warn"},Ce=B({__name:"WorkbenchHeader",props:{steps:{},stepStates:{},currentStep:{},draft:{},packageNameOk:{type:Boolean},memberCount:{},errorCount:{},warningCount:{}},emits:["go"],setup(e){return(s,n)=>(i(),o("header",be,[t("div",fe,[t("div",ke,[t("h1",null,v(e.currentStep.label),1),t("p",null,v(e.currentStep.description),1)]),t("div",ge,[t("span",{class:M(["bw-pkg-name",{"is-warn":!e.packageNameOk}])},v(e.draft.packageName||"未填写包名"),3),t("span",pe,v(e.draft.version||"0.0.0"),1),t("span",ye,v(e.draft.distTag||"alpha"),1),t("span",we,v(e.memberCount)+" 成员",1),e.errorCount?(i(),o("span",he,v(e.errorCount)+" 错误",1)):e.warningCount?(i(),o("span",$e,v(e.warningCount)+" 警告",1)):w("v-if",true)])]),n[1]||(n[1]=t("div",{class:"bw-header-rule"},null,-1)),b(me,{steps:e.steps,"step-states":e.stepStates,onGo:n[0]||(n[0]=l=>s.$emit("go",l))},null,8,["steps","step-states"])]))}}),je={class:"bw-footer"},xe={class:"bw-footer-left"},Ve={class:"bw-footer-hint"},Re={class:"bw-footer-right"},Se=B({__name:"WorkbenchFooter",props:{primaryActionKind:{},primaryDisabled:{type:Boolean},blockReason:{},footerHint:{},isFirst:{type:Boolean},isLast:{type:Boolean},busyValidate:{type:Boolean},busyGenerate:{type:Boolean}},emits:["prev","next","validate","generate"],setup(e){return(s,n)=>{const l=P("el-button");return i(),o("footer",je,[t("div",xe,[b(l,{disabled:e.isFirst,onClick:n[0]||(n[0]=a=>s.$emit("prev"))},{default:C(()=>[...n[4]||(n[4]=[$("上一步",-1)])]),_:1},8,["disabled"])]),t("div",Ve,[t("span",{class:M(e.blockReason?"is-warn":"is-muted")},v(e.footerHint),3)]),t("div",Re,[e.primaryActionKind==="next"?(i(),z(l,{key:0,type:"primary",disabled:e.primaryDisabled||e.isLast,onClick:n[1]||(n[1]=a=>s.$emit("next"))},{default:C(()=>[...n[5]||(n[5]=[$("下一步",-1)])]),_:1},8,["disabled"])):e.primaryActionKind==="validate"?(i(),z(l,{key:1,type:"primary",loading:e.busyValidate,onClick:n[2]||(n[2]=a=>s.$emit("validate"))},{default:C(()=>[...n[6]||(n[6]=[$("运行校验",-1)])]),_:1},8,["loading"])):(i(),z(l,{key:2,type:"primary",loading:e.busyGenerate,onClick:n[3]||(n[3]=a=>s.$emit("generate"))},{default:C(()=>[...n[7]||(n[7]=[$("生成文件",-1)])]),_:1},8,["loading"]))])])}}}),Oe={class:"bw-card"},Pe={class:"bw-form-grid"},Ee={class:"bw-span-2"},Ne={class:"bw-span-2"},ze={class:"bw-span-2"},Ae={key:0,class:"bw-form-error is-danger"},Te=B({__name:"ProjectStep",props:{api:{}},setup(e){return(s,n)=>{const l=P("el-input");return i(),o("section",Oe,[n[15]||(n[15]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"项目基础信息"),t("p",null,[$("真实 npm 包名必须是小写的 "),t("code",null,"koishi-plugin-pa-*"),$(" 或 "),t("code",null,"@scope/koishi-plugin-pa-*"),$("。")])])],-1)),t("div",Pe,[t("label",null,[n[7]||(n[7]=t("span",null,"包名",-1)),b(l,{modelValue:e.api.draft.packageName,"onUpdate:modelValue":n[0]||(n[0]=a=>e.api.draft.packageName=a),placeholder:"koishi-plugin-pa-demo"},null,8,["modelValue"])]),t("label",null,[n[8]||(n[8]=t("span",null,"版本",-1)),b(l,{modelValue:e.api.draft.version,"onUpdate:modelValue":n[1]||(n[1]=a=>e.api.draft.version=a),placeholder:"0.1.0-alpha.0"},null,8,["modelValue"])]),t("label",null,[n[9]||(n[9]=t("span",null,"显示名称",-1)),b(l,{modelValue:e.api.draft.label,"onUpdate:modelValue":n[2]||(n[2]=a=>e.api.draft.label=a),placeholder:"Dialogue 插件包"},null,8,["modelValue"])]),t("label",null,[n[10]||(n[10]=t("span",null,"dist-tag",-1)),b(l,{modelValue:e.api.draft.distTag,"onUpdate:modelValue":n[3]||(n[3]=a=>e.api.draft.distTag=a),placeholder:"alpha"},null,8,["modelValue"])]),t("label",Ee,[n[11]||(n[11]=t("span",null,"描述",-1)),b(l,{modelValue:e.api.draft.description,"onUpdate:modelValue":n[4]||(n[4]=a=>e.api.draft.description=a),type:"textarea",rows:3,placeholder:"说明这个插件包解决什么场景,包含哪些能力。"},null,8,["modelValue"])]),t("label",Ne,[n[12]||(n[12]=t("span",null,"Keywords (逗号分隔)",-1)),b(l,{modelValue:e.api.keywordsText.value,"onUpdate:modelValue":n[5]||(n[5]=a=>e.api.keywordsText.value=a),placeholder:"koishi, plugin, market:package"},null,8,["modelValue"])]),t("label",ze,[n[13]||(n[13]=t("span",null,"项目目录",-1)),b(l,{modelValue:e.api.projectPath.value,"onUpdate:modelValue":n[6]||(n[6]=a=>e.api.projectPath.value=a),placeholder:"相对 Koishi baseDir 或绝对路径"},null,8,["modelValue"])])]),e.api.packageNameOk.value?w("v-if",true):(i(),o("p",Ae,[...n[14]||(n[14]=[$(" 包名格式不合法,需要 ",-1),t("code",null,"koishi-plugin-pa-*",-1),$(" 或 ",-1),t("code",null,"@scope/koishi-plugin-pa-*",-1),$("。 ",-1)])])),n[16]||(n[16]=t("p",{class:"bw-form-note is-muted"},[$(" 工作台仅生成 "),t("code",null,"package.json"),$("、"),t("code",null,"README.md"),$(" 和 "),t("code",null,"lib/index.js"),$(";不会执行 npm publish。 ")],-1))])}}}),Ue=/^@koishijs\/plugin-[0-9a-z-]+$|(^|\/)koishi-plugin-[0-9a-z-]+$/,Ke=/^(?:@[0-9a-z-]+\/)?koishi-plugin-pa-[0-9a-z-]+$/,Be=/(command|script|exec|path|token|secret|password|sql|url|webhook|key)/i;function G(e=""){return e.trim().toLowerCase()}function J(e=""){return e.toLowerCase().replace(/(koishi-|^@koishijs\/)plugin-/,"")}function Ie(e=""){return Ue.test(e)}function Me(e=""){return Ke.test(e.trim())}function De(e){return e?/^[0-9]+\.[0-9]+\.[0-9]+/.test(e)?`^${e}`:e:"^1.0.0"}function Le(){return Math.random().toString(36).slice(2,10)}function W(e){return!e||typeof e!="object"?{}:Object.fromEntries(Object.entries(e).filter(([s])=>!s.startsWith("$")).map(([s,n])=>Array.isArray(n)?[s,n.map(l=>_(l))]:n&&typeof n=="object"?[s,W(n)]:[s,n]))}function _(e){return Array.isArray(e)?e.map(s=>_(s)):e&&typeof e=="object"?W(e):e}function ee(e,s="",n=new Set){if(!e||typeof e!="object")return n;for(const[l,a]of Object.entries(e)){const p=s?`${s}.${l}`:l;Be.test(l)&&n.add(p),a&&typeof a=="object"&&ee(a,p,n)}return n}function Y(e,s){if(!(!e||typeof e!="object"))for(const n of Object.keys(e)){if(n.startsWith("$"))continue;const l=e[n],[a]=n.split(":",1);if(a.replace(/^~/,"")===s)return l;const d=Y(l,s);if(d)return d}}function We(e){return e.split(/[\s,,;;]+/g).map(s=>s.trim()).filter(Boolean)}const Fe={class:"bw-member-row"},Je={class:"bw-tr bw-row-main"},Ge={class:"bw-cell-name"},qe=["aria-expanded"],He={class:"bw-name-block"},Ze={class:"is-muted"},Ye={class:"bw-cell-version"},Qe={class:"bw-cell-type"},Xe={class:"bw-cell-status bw-status-line"},_e={key:0},et={key:1},tt={key:2,title:"该标记来自市场索引,不等于安全审计。"},nt={key:3,class:"is-danger"},at={key:4,class:"is-danger"},lt={key:5,class:"is-accent"},st={class:"bw-cell-actions"},it={key:0,class:"bw-tr bw-row-detail"},ot={class:"bw-detail-grid"},rt=B({__name:"MemberRow",props:{member:{},isFirst:{type:Boolean},isLast:{type:Boolean},expanded:{type:Boolean},localVersion:{},hasSchema:{type:Boolean},hasPreset:{type:Boolean},market:{}},emits:["toggle","move","remove","updatePackage","updatePluginKey"],setup(e){const s=e,n=N(()=>J(s.member.package));return(l,a)=>{var k,c,j;const p=P("el-input"),d=P("el-option"),u=P("el-select"),S=P("el-button");return i(),o("div",Fe,[t("div",Je,[t("div",Ge,[t("button",{type:"button",class:"bw-expander","aria-expanded":e.expanded,onClick:a[0]||(a[0]=R=>l.$emit("toggle"))},v(e.expanded?"▾":"▸"),9,qe),t("div",He,[t("strong",null,v(n.value||"未命名"),1),t("span",Ze,v(e.member.package||"等待输入包名"),1)])]),t("div",Ye,[b(p,{modelValue:e.member.version,"onUpdate:modelValue":a[1]||(a[1]=R=>e.member.version=R),placeholder:"^1.0.0",size:"small"},null,8,["modelValue"])]),t("div",Qe,[b(u,{modelValue:e.member.required,"onUpdate:modelValue":a[2]||(a[2]=R=>e.member.required=R),size:"small"},{default:C(()=>[b(d,{value:true,label:"required"}),b(d,{value:false,label:"optional"})]),_:1},8,["modelValue"])]),t("div",Xe,[e.localVersion?(i(),o("span",_e,"local "+v(e.localVersion),1)):w("v-if",true),e.hasSchema?(i(),o("span",et,"runtime schema")):w("v-if",true),(k=e.market)!=null&&k.verified?(i(),o("span",tt,"市场认证")):w("v-if",true),(c=e.market)!=null&&c.insecure?(i(),o("span",nt,"风险标记")):w("v-if",true),(j=e.market)!=null&&j.deprecated?(i(),o("span",at,"已废弃")):w("v-if",true),e.hasPreset?(i(),o("span",lt,"含预设配置")):w("v-if",true)]),t("div",st,[b(S,{text:"",size:"small",disabled:e.isFirst,onClick:a[3]||(a[3]=R=>l.$emit("move",-1))},{default:C(()=>[...a[8]||(a[8]=[$("↑",-1)])]),_:1},8,["disabled"]),b(S,{text:"",size:"small",disabled:e.isLast,onClick:a[4]||(a[4]=R=>l.$emit("move",1))},{default:C(()=>[...a[9]||(a[9]=[$("↓",-1)])]),_:1},8,["disabled"]),b(S,{text:"",size:"small",type:"danger",onClick:a[5]||(a[5]=R=>l.$emit("remove"))},{default:C(()=>[...a[10]||(a[10]=[$("移除",-1)])]),_:1})])]),e.expanded?(i(),o("div",it,[t("div",ot,[t("label",null,[a[11]||(a[11]=t("span",null,"完整包名",-1)),b(p,{"model-value":e.member.package,size:"small","onUpdate:modelValue":a[6]||(a[6]=R=>l.$emit("updatePackage",R))},null,8,["model-value"])]),t("label",null,[a[12]||(a[12]=t("span",null,"plugin 键",-1)),b(p,{"model-value":e.member.plugin,size:"small","onUpdate:modelValue":a[7]||(a[7]=R=>l.$emit("updatePluginKey",R))},null,8,["model-value"])])])])):w("v-if",true)])}}}),ut={class:"bw-card bw-add-card"},dt={class:"bw-add-grid"},ct={class:"bw-add-source"},vt={class:"bw-add-source"},mt={class:"bw-card"},bt={class:"bw-card-head"},ft={class:"is-muted"},kt={key:0,class:"bw-empty"},gt={key:1,class:"bw-table"},pt=B({__name:"MembersStep",props:{api:{}},setup(e){const s=e,n=T(""),l=T(""),a=T(new Set);function p(k){const c=new Set(a.value);c.has(k)?c.delete(k):c.add(k),a.value=c}function d(){n.value&&(s.api.addMember(n.value),n.value="")}function u(){s.api.addMember(l.value),l.value=""}function S(k,c){k.package=c,s.api.syncPluginKey(k)}return(k,c)=>{const j=P("el-option"),R=P("el-select"),D=P("el-button"),L=P("el-input");return i(),o(K,null,[t("section",ut,[c[6]||(c[6]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"添加成员"),t("p",null,"从已安装插件中选择,或手动输入 npm 包名。")])],-1)),t("div",dt,[t("div",ct,[c[3]||(c[3]=t("span",{class:"bw-add-label is-muted"},"已安装",-1)),b(R,{modelValue:n.value,"onUpdate:modelValue":c[0]||(c[0]=f=>n.value=f),filterable:"",clearable:"",disabled:!e.api.installedOptions.value.length,placeholder:e.api.installedOptions.value.length?"选择已安装插件":"没有可选的已安装插件"},{default:C(()=>[(i(true),o(K,null,I(e.api.installedOptions.value,f=>(i(),z(j,{key:f.name,value:f.name,label:f.label},null,8,["value","label"]))),128))]),_:1},8,["modelValue","disabled","placeholder"]),b(D,{type:"primary",disabled:!n.value,onClick:d},{default:C(()=>[...c[2]||(c[2]=[$("加入",-1)])]),_:1},8,["disabled"])]),t("div",vt,[c[5]||(c[5]=t("span",{class:"bw-add-label is-muted"},"手动添加",-1)),b(L,{modelValue:l.value,"onUpdate:modelValue":c[1]||(c[1]=f=>l.value=f),placeholder:"koishi-plugin-example",onKeyup:se(u,["enter"])},null,8,["modelValue"]),b(D,{type:"primary",plain:"",disabled:!l.value.trim(),onClick:u},{default:C(()=>[...c[4]||(c[4]=[$("添加",-1)])]),_:1},8,["disabled"])])])]),t("section",mt,[t("div",bt,[t("div",null,[t("h2",null,[c[7]||(c[7]=$("成员列表 ",-1)),t("span",ft,"("+v(e.api.members.length)+")",1)]),c[8]||(c[8]=t("p",null,"required 默认加入安装计划,optional 默认作为可选项展示。",-1))])]),e.api.members.length?(i(),o("div",gt,[c[9]||(c[9]=t("div",{class:"bw-tr bw-th bw-row-main"},[t("div",null,"包名"),t("div",null,"版本范围"),t("div",null,"类型"),t("div",null,"状态"),t("div",null,"操作")],-1)),(i(true),o(K,null,I(e.api.members,(f,E)=>{var m,g;return i(),z(rt,{key:f.id,member:f,"is-first":E===0,"is-last":E===e.api.members.length-1,expanded:a.value.has(f.id),"local-version":(g=(m=e.api.packageInfo(f.package))==null?void 0:m.package)==null?void 0:g.version,"has-schema":!!e.api.runtimeSchema(f),"has-preset":e.api.hasPresetConfig(f),market:e.api.marketInfo(f.package),onToggle:O=>p(f.id),onMove:O=>e.api.moveMember(E,O),onRemove:O=>e.api.removeMember(E),onUpdatePackage:O=>S(f,O),onUpdatePluginKey:O=>e.api.updatePluginKey(f,O)},null,8,["member","is-first","is-last","expanded","local-version","has-schema","has-preset","market","onToggle","onMove","onRemove","onUpdatePackage","onUpdatePluginKey"])}),128))])):(i(),o("div",kt," 还没有添加成员。从上面的两种方式选择一个开始。 "))])],64)}}}),yt={class:"bw-config-editor bw-card"},wt={class:"bw-card-head"},ht={class:"is-muted"},$t={class:"bw-toolbar"},Ct={key:0,class:"bw-sensitive"},jt={class:"is-muted"},xt={class:"bw-tabs",role:"tablist"},Vt=["disabled","title"],Rt={key:1,class:"bw-tab-body"},St={key:2,class:"bw-tab-body"},Ot={class:"bw-tab-actions"},Pt={key:0,class:"is-danger"},Et={key:1,class:"is-muted"},Nt=B({__name:"ConfigEditor",props:{member:{},schema:{},sensitiveKeys:{}},emits:["copyExisting","reset","updateObject","syncFromText"],setup(e){const s=e,n=N(()=>!!s.schema),l=T(n.value?"form":"json");ie(n,d=>{!d&&l.value==="form"&&(l.value="json")});function a(d){d==="form"&&!n.value||(l.value=d)}const p=N(()=>J(s.member.package));return(d,u)=>{const S=P("el-button"),k=P("k-form"),c=P("el-input");return i(),o("article",yt,[t("div",wt,[t("div",null,[t("h3",null,v(p.value),1),t("p",ht,v(e.member.package),1)]),t("div",$t,[b(S,{size:"small",onClick:u[0]||(u[0]=j=>d.$emit("copyExisting"))},{default:C(()=>[...u[7]||(u[7]=[$("复制已有配置",-1)])]),_:1}),b(S,{size:"small",onClick:u[1]||(u[1]=j=>d.$emit("reset"))},{default:C(()=>[...u[8]||(u[8]=[$("清空",-1)])]),_:1})])]),e.sensitiveKeys.length?(i(),o("div",Ct,[u[9]||(u[9]=t("strong",{class:"is-warn"},"敏感字段",-1)),t("span",jt,v(e.sensitiveKeys.join(", ")),1)])):w("v-if",true),t("div",xt,[t("button",{type:"button",class:M({active:l.value==="form"}),disabled:!n.value,title:n.value?"":"未读取到 schema",role:"tab",onClick:u[2]||(u[2]=j=>a("form"))},"表单",10,Vt),t("button",{type:"button",class:M({active:l.value==="json"}),role:"tab",onClick:u[3]||(u[3]=j=>a("json"))},"JSON",2)]),l.value==="form"&&n.value?(i(),o("div",Rt,[b(k,{schema:e.schema,initial:e.member.configObject,"model-value":e.member.configObject,"onUpdate:modelValue":u[4]||(u[4]=j=>d.$emit("updateObject",j))},null,8,["schema","initial","model-value"])])):(i(),o("div",St,[b(c,{modelValue:e.member.configText,"onUpdate:modelValue":u[5]||(u[5]=j=>e.member.configText=j),type:"textarea",rows:9,spellcheck:"false"},null,8,["modelValue"]),t("div",Ot,[b(S,{size:"small",onClick:u[6]||(u[6]=j=>d.$emit("syncFromText"))},{default:C(()=>[...u[10]||(u[10]=[$("解析 JSON",-1)])]),_:1}),e.member.configError?(i(),o("span",Pt,v(e.member.configError),1)):n.value?w("v-if",true):(i(),o("span",Et,"该成员未读取到 schema,只能在 JSON 模式编辑。"))])]))])}}}),zt={class:"bw-card"},At={key:0,class:"bw-empty"},Tt=B({__name:"ConfigStep",props:{api:{}},setup(e){return(s,n)=>(i(),o(K,null,[t("section",zt,[n[0]||(n[0]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"配置审计"),t("p",null,"预设配置会随插件包公开,敏感字段应在发布前逐项确认。")])],-1)),e.api.members.length?w("v-if",true):(i(),o("p",At,"先添加成员插件。"))]),(i(true),o(K,null,I(e.api.members,l=>(i(),z(Nt,{key:l.id,member:l,schema:e.api.runtimeSchema(l),"sensitive-keys":e.api.sensitiveKeys(l),onCopyExisting:a=>e.api.copyExistingConfig(l),onReset:a=>e.api.resetConfig(l),onUpdateObject:a=>e.api.updateConfigObject(l,a),onSyncFromText:a=>e.api.syncConfigText(l)},null,8,["member","schema","sensitive-keys","onCopyExisting","onReset","onUpdateObject","onSyncFromText"]))),128))],64))}}),Ut={class:"bw-card"},Kt={class:"bw-card-head"},Bt={class:"bw-toolbar"},It={key:0,class:"bw-validate-grid"},Mt={class:"bw-validate-summary"},Dt={class:"is-muted"},Lt={key:0,class:"bw-validate-npm"},Wt={class:"is-muted"},Ft={class:"bw-validate-issues"},Jt={key:0,class:"is-muted"},Gt={key:0,class:"bw-issue-path"},qt={key:1,class:"bw-empty"},Ht=B({__name:"ValidateStep",props:{actions:{}},setup(e){return(s,n)=>{const l=P("el-button");return i(),o("section",Ut,[t("div",Kt,[n[1]||(n[1]=t("div",null,[t("h2",null,"npm 与清单校验"),t("p",null,"检查包名、版本占用、成员包存在性、版本范围、自引用、重复成员和直接循环。")],-1)),t("div",Bt,[b(l,{type:"primary",loading:e.actions.busy.validate,onClick:e.actions.validate},{default:C(()=>[...n[0]||(n[0]=[$(" 运行校验 ",-1)])]),_:1},8,["loading","onClick"])])]),e.actions.validation.value?(i(),o("div",It,[t("div",Mt,[t("strong",{class:M(e.actions.validation.value.valid?"is-ok":"is-danger")},v(e.actions.validation.value.valid?"校验通过":"校验未通过"),3),t("span",Dt,v(e.actions.errorCount.value)+" 个错误,"+v(e.actions.warningCount.value)+" 个警告 ",1)]),e.actions.npmEntries.value.length?(i(),o("div",Lt,[n[2]||(n[2]=t("h3",null,"npm 检查",-1)),(i(true),o(K,null,I(e.actions.npmEntries.value,a=>(i(),o("div",{key:a.name,class:"bw-validate-npm-item"},[t("div",null,[t("strong",null,v(a.name),1),t("span",Wt,v(a.exists?`latest ${a.latest||"-"}`:a.error||"not found"),1)]),t("span",{class:M(a.exists?"is-ok":"is-danger")},v(a.exists?"存在":"缺失"),3)]))),128))])):w("v-if",true),t("div",Ft,[n[3]||(n[3]=t("h3",null,"问题列表",-1)),e.actions.validation.value.issues.length?w("v-if",true):(i(),o("p",Jt,"没有发现问题。")),(i(true),o(K,null,I(e.actions.validation.value.issues,(a,p)=>(i(),o("div",{key:p,class:M(["bw-issue",a.level])},[t("strong",null,v(a.level),1),t("span",null,[a.path?(i(),o("span",Gt,v(a.path)+":",1)):w("v-if",true),$(v(a.message),1)])],2))),128))])])):(i(),o("p",qt,"点击运行校验后显示结果。"))])}}}),Zt={key:0,class:"bw-result-panel"},Yt={key:0,class:"bw-result-head"},Qt={key:0,class:"is-muted"},H=B({__name:"ResultPanel",props:{title:{},subtitle:{},status:{}},setup(e){return(s,n)=>e.title||s.$slots.default?(i(),o("section",Zt,[e.title?(i(),o("div",Yt,[t("strong",{class:M(e.status)},v(e.title),3),e.subtitle?(i(),o("span",Qt,v(e.subtitle),1)):w("v-if",true)])):w("v-if",true),oe(s.$slots,"default")])):w("v-if",true)}}),Xt={class:"bw-card"},_t={class:"bw-card-head"},en={class:"bw-toolbar"},tn={class:"bw-download-grid"},nn=["disabled"],an={key:0,class:"bw-download-busy is-accent"},ln=["disabled"],sn={key:0,class:"bw-download-busy is-accent"},on={key:0,class:"is-muted"},rn={key:1,class:"bw-issue-warnings"},un={key:2,class:"bw-file-list"},dn={key:0,class:"is-muted"},cn={class:"bw-card"},vn={class:"bw-write-controls bw-toolbar"},mn={class:"is-muted"},bn={class:"bw-checkbox-line"},fn={class:"bw-file-list"},kn={key:0,class:"is-warn"},gn={key:1,class:"is-ok"},pn={key:2,class:"is-muted"},yn={key:0,class:"bw-pack-files"},wn={key:0,class:"is-muted"},hn={key:1,class:"bw-pre"},$n={key:0,class:"bw-card"},Cn={class:"bw-pre"},jn={class:"bw-pre"},xn={class:"bw-pre"},Vn={class:"bw-pre"},Rn={class:"bw-pre"},Sn=B({__name:"ReleaseStep",props:{actions:{},projectPath:{}},setup(e){const s=T(false),n=T("package");return(l,a)=>{const p=P("el-button"),d=P("el-checkbox"),u=P("el-tab-pane"),S=P("el-tabs");return i(),o(K,null,[t("section",Xt,[t("div",_t,[a[8]||(a[8]=t("div",null,[t("h2",null,"下载与发布"),t("p",null,"下载 npm 发布包或源码 zip,使用本机 npm 登录态发布。")],-1)),t("div",en,[b(p,{loading:e.actions.busy.generate,onClick:e.actions.generate},{default:C(()=>[...a[6]||(a[6]=[$("生成文件",-1)])]),_:1},8,["loading","onClick"]),b(p,{disabled:!e.actions.generated.value,onClick:e.actions.copyAll},{default:C(()=>[...a[7]||(a[7]=[$("复制全部输出",-1)])]),_:1},8,["disabled","onClick"])])]),t("div",tn,[t("button",{type:"button",class:"bw-download-card primary",disabled:e.actions.busy.archive==="npm-tgz",onClick:a[0]||(a[0]=k=>e.actions.downloadArchive("npm-tgz"))},[a[9]||(a[9]=t("span",{class:"bw-download-title"},"下载 npm 发布包",-1)),a[10]||(a[10]=t("span",{class:"bw-download-desc is-muted"},"真实 npm pack 产物,下载后可直接发布。",-1)),e.actions.busy.archive==="npm-tgz"?(i(),o("span",an,"正在打包…")):w("v-if",true)],8,nn),t("button",{type:"button",class:"bw-download-card",disabled:e.actions.busy.archive==="source-zip",onClick:a[1]||(a[1]=k=>e.actions.downloadArchive("source-zip"))},[a[11]||(a[11]=t("span",{class:"bw-download-title"},"下载源码 zip",-1)),a[12]||(a[12]=t("span",{class:"bw-download-desc is-muted"},"可审查的项目源码,自行解压发布。",-1)),e.actions.busy.archive==="source-zip"?(i(),o("span",sn,"正在压缩…")):w("v-if",true)],8,ln)]),e.actions.archiveResult.value?(i(),z(H,{key:0,title:e.actions.archiveResult.value.ok?"压缩包已生成":e.actions.archiveResult.value.error||"压缩包生成失败",status:e.actions.archiveResult.value.ok?"is-ok":"is-danger",subtitle:e.actions.archiveResult.value.filename?`文件:${e.actions.archiveResult.value.filename}`:void 0},{default:C(()=>{var k,c;return[e.actions.archiveResult.value.command?(i(),o("p",on,[a[13]||(a[13]=$(" 发布命令:",-1)),t("code",null,v(e.actions.archiveResult.value.command),1)])):w("v-if",true),(k=e.actions.archiveResult.value.warnings)!=null&&k.length?(i(),o("div",rn,[(i(true),o(K,null,I(e.actions.archiveResult.value.warnings,(j,R)=>(i(),o("p",{key:R,class:"is-warn"},v(j.path?`${j.path}:`:"")+v(j.message),1))),128))])):w("v-if",true),(c=e.actions.archiveResult.value.files)!=null&&c.length?(i(),o("div",un,[(i(true),o(K,null,I(e.actions.archiveResult.value.files.slice(0,8),j=>(i(),o("p",{key:j.path},[t("code",null,v(j.path),1),j.size?(i(),o("span",dn,v(j.size)+" bytes",1)):w("v-if",true)]))),128))])):w("v-if",true)]}),_:1},8,["title","status","subtitle"])):w("v-if",true)]),t("section",cn,[a[20]||(a[20]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"写入项目"),t("p",null,"写入 ProjectStep 中填写的项目目录。预览模式不会修改磁盘。")])],-1)),t("div",vn,[t("span",mn,[a[14]||(a[14]=$("目录:",-1)),t("code",null,v(e.projectPath||"未填写"),1)]),a[19]||(a[19]=t("span",{class:"bw-toolbar-spacer"},null,-1)),t("label",bn,[b(d,{modelValue:s.value,"onUpdate:modelValue":a[2]||(a[2]=k=>s.value=k)},null,8,["modelValue"]),a[15]||(a[15]=t("span",{class:"is-muted"},"允许覆盖",-1))]),b(p,{loading:e.actions.busy.previewWrite,disabled:!e.actions.generated.value||!e.projectPath,onClick:a[3]||(a[3]=k=>e.actions.previewWrite(s.value))},{default:C(()=>[...a[16]||(a[16]=[$("预览",-1)])]),_:1},8,["loading","disabled"]),b(p,{type:"primary",loading:e.actions.busy.write,disabled:!e.actions.generated.value||!e.projectPath,onClick:a[4]||(a[4]=k=>e.actions.writeToDisk(s.value))},{default:C(()=>[...a[17]||(a[17]=[$("写入项目",-1)])]),_:1},8,["loading","disabled"]),b(p,{loading:e.actions.busy.pack,disabled:!e.projectPath,onClick:e.actions.packDryRun},{default:C(()=>[...a[18]||(a[18]=[$(" npm pack --dry-run ",-1)])]),_:1},8,["loading","disabled","onClick"])]),e.actions.writeResult.value?(i(),z(H,{key:0,title:e.actions.writeResult.value.ok?"文件检查通过":e.actions.writeResult.value.error||"仍有文件被跳过或写入失败",status:e.actions.writeResult.value.ok?"is-ok":"is-warn",subtitle:e.actions.writeResult.value.root?`目标:${e.actions.writeResult.value.root}`:void 0},{default:C(()=>[t("div",fn,[(i(true),o(K,null,I(e.actions.writeResult.value.files,k=>(i(),o("p",{key:k.path},[t("code",null,v(k.path),1),k.skipped?(i(),o("span",kn,"已存在,未覆盖")):k.written?(i(),o("span",gn,"已写入")):(i(),o("span",pn,"将写入"))]))),128))])]),_:1},8,["title","status","subtitle"])):w("v-if",true),e.actions.packResult.value?(i(),z(H,{key:1,title:e.actions.packResult.value.ok?"dry-run 通过":e.actions.packResult.value.error||"dry-run 失败",status:e.actions.packResult.value.ok?"is-ok":"is-danger"},{default:C(()=>{var k;return[(k=e.actions.packResult.value.files)!=null&&k.length?(i(),o("ul",yn,[(i(true),o(K,null,I(e.actions.packResult.value.files.slice(0,12),c=>(i(),o("li",{key:c.path},[t("code",null,v(c.path),1),c.size?(i(),o("span",wn,v(c.size)+" bytes",1)):w("v-if",true)]))),128))])):w("v-if",true),e.actions.packResult.value.stderr?(i(),o("pre",hn,v(e.actions.packResult.value.stderr),1)):w("v-if",true)]}),_:1},8,["title","status"])):w("v-if",true)]),e.actions.generated.value?(i(),o("section",$n,[a[21]||(a[21]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"生成内容预览"),t("p",null,"核对每个文件的内容,确认无误后再下载或写入。")])],-1)),b(S,{modelValue:n.value,"onUpdate:modelValue":a[5]||(a[5]=k=>n.value=k),class:"bw-output-tabs"},{default:C(()=>[b(u,{label:"package.json",name:"package"},{default:C(()=>[t("pre",Cn,v(e.actions.generated.value.packageJson),1)]),_:1}),b(u,{label:"koishi.bundle",name:"bundle"},{default:C(()=>[t("pre",jn,v(e.actions.generated.value.bundleJson),1)]),_:1}),b(u,{label:"lib/index.js",name:"lib"},{default:C(()=>[t("pre",xn,v(e.actions.generated.value.libIndex),1)]),_:1}),b(u,{label:"README",name:"readme"},{default:C(()=>[t("pre",Vn,v(e.actions.generated.value.readme),1)]),_:1}),b(u,{label:"发布命令",name:"commands"},{default:C(()=>[t("pre",Rn,v(e.actions.generated.value.publishCommands.join(`
2
- `)),1)]),_:1})]),_:1},8,["modelValue"])])):w("v-if",true)],64)}}});function X(){return q.packages??{}}function On(){var e;return((e=q.market)==null?void 0:e.data)??{}}function Pn(){const e=Z({packageName:"koishi-plugin-pa-demo",version:"0.1.0-alpha.0",label:"",description:"",distTag:"alpha"}),s=Z([]),n=T("koishi, plugin, market:package"),l=T(""),a=N(()=>Me(e.packageName)),p=N(()=>s.filter(c).length),d=N(()=>Object.values(X()).filter(r=>{var y;return Ie((y=r==null?void 0:r.package)==null?void 0:y.name)}).sort((r,y)=>r.package.name.localeCompare(y.package.name)).map(r=>({name:r.package.name,label:`${r.package.name}@${r.package.version}`})));function u(r){return X()[G(r)]}function S(r){return On()[G(r)]}function k(r){var y,V;return(V=(y=u(r.package))==null?void 0:y.runtime)==null?void 0:V.schema}function c(r){return!!r.configObject&&Object.keys(r.configObject).length>0}function j(r){return[...ee(r.configObject)].slice(0,8)}function R(r,y){var A,Q;const V=G(r);if(V){if(s.some(ae=>ae.package===V)){x.warning("这个成员已经在列表中。");return}s.push({id:Le(),package:V,plugin:J(V),version:De(y??((Q=(A=u(V))==null?void 0:A.package)==null?void 0:Q.version)),required:true,configText:"{}",configObject:{},autoPlugin:true})}}function D(r){s.splice(r,1)}function L(r,y){const V=r+y;if(V<0||V>=s.length)return;const[A]=s.splice(r,1);s.splice(V,0,A)}function f(r){(r.autoPlugin||!r.plugin)&&(r.plugin=J(r.package),r.autoPlugin=true)}function E(r,y){r.plugin=y,r.autoPlugin=y===J(r.package)}function m(r,y){r.configObject=W(y),r.configText=JSON.stringify(r.configObject,null,2),r.configError=""}function g(r){m(r,{})}function O(r,y){r.configObject=W(y),r.configText=JSON.stringify(r.configObject,null,2),r.configError=""}function U(r){try{const y=JSON.parse(r.configText||"{}");return!y||typeof y!="object"||Array.isArray(y)?(r.configError="预设配置必须是对象。",false):(r.configObject=W(y),r.configText=JSON.stringify(r.configObject,null,2),r.configError="",x.success("已从 JSON 更新表单。"),true)}catch(y){return r.configError=y instanceof Error?y.message:String(y),false}}function te(r){var A;const y=(A=q.config)==null?void 0:A.plugins,V=Y(y,r.plugin)??Y(y,r.package);if(!V){x.warning("没有找到已有配置。");return}m(r,W(V))}function ne(){const r={...e,keywords:We(n.value),members:[]};for(const[y,V]of s.entries()){let A;try{A=JSON.parse(V.configText||"{}")}catch{x.error(`第 ${y+1} 个成员的预设配置不是合法 JSON。`);return}if(!A||typeof A!="object"||Array.isArray(A)){x.error(`第 ${y+1} 个成员的预设配置必须是对象。`);return}V.configObject=W(A),V.configError="",r.members.push({package:G(V.package),plugin:V.plugin.trim().toLowerCase(),version:V.version.trim(),required:V.required,config:A})}return r}return{draft:e,members:s,keywordsText:n,projectPath:l,packageNameOk:a,presetCount:p,installedOptions:d,packageInfo:u,marketInfo:S,runtimeSchema:k,hasPresetConfig:c,sensitiveKeys:j,addMember:R,removeMember:D,moveMember:L,syncPluginKey:f,updatePluginKey:E,setConfig:m,resetConfig:g,updateConfigObject:O,syncConfigText:U,copyExistingConfig:te,buildPayload:ne}}function En(e){const s=T(),n=T(),l=T(),a=T(),p=T(),d=Z({validate:false,generate:false,pack:false,previewWrite:false,write:false,archive:""}),u=N(()=>{var m;return((m=s.value)==null?void 0:m.issues.filter(g=>g.level==="error").length)??0}),S=N(()=>{var m;return((m=s.value)==null?void 0:m.issues.filter(g=>g.level==="warning").length)??0}),k=N(()=>{var m;return Object.values(((m=s.value)==null?void 0:m.npm)??{})});async function c(){const m=e.buildPayload();if(m){d.validate=true;try{s.value=await F("bundle-workbench/validate",m),s.value.valid?x.success("校验通过。"):x.warning("校验完成,仍有问题需要处理。")}catch(g){console.error(g),x.error("校验失败。")}finally{d.validate=false}}}async function j(){const m=e.buildPayload();if(m){d.generate=true;try{n.value=await F("bundle-workbench/generate",m),x.success("已生成插件包文件内容。")}catch(g){console.error(g),x.error("生成失败。")}finally{d.generate=false}}}async function R(m){const g=e.buildPayload();if(g){d.previewWrite=true;try{l.value=await F("bundle-workbench/write-files",e.projectPath.value,g,{dryRun:true,overwrite:m}),l.value.ok?x.success("写入预览通过。"):x.warning(l.value.error||"写入预览完成,有文件会被跳过。")}catch(O){console.error(O),x.error("写入预览失败。")}finally{d.previewWrite=false}}}async function D(m){const g=e.buildPayload();if(g){d.write=true;try{l.value=await F("bundle-workbench/write-files",e.projectPath.value,g,{overwrite:m}),l.value.ok?x.success("已写入插件包项目。"):x.warning(l.value.error||"部分文件被跳过,开启覆盖后可重试。")}catch(O){console.error(O),x.error("写入失败。")}finally{d.write=false}}}async function L(){d.pack=true;try{a.value=await F("bundle-workbench/pack-dry-run",e.projectPath.value),a.value.ok?x.success("dry-run 通过。"):x.error("dry-run 失败。")}catch(m){console.error(m),x.error("dry-run 调用失败。")}finally{d.pack=false}}async function f(m){var O;const g=e.buildPayload();if(g){d.archive=m;try{p.value=await F("bundle-workbench/download-archive",g,m);const U=p.value;if(!U.ok||!U.base64||!U.filename){x.error(U.error||"压缩包生成失败。");return}Nn(U.base64,U.filename,U.mime),(O=U.warnings)!=null&&O.length?x.warning(`已下载,但仍有 ${U.warnings.length} 个警告需要留意。`):x.success("压缩包已下载。")}catch(U){console.error(U),x.error("压缩包生成失败。")}finally{d.archive=""}}}async function E(){var g;if(!n.value)return;const m=["--- package.json ---",n.value.packageJson,"--- koishi.bundle ---",n.value.bundleJson,"--- lib/index.js ---",n.value.libIndex,"--- README.md ---",n.value.readme,"--- commands ---",n.value.publishCommands.join(`
1
+ import{store as _,message as S,send as G,icons as de}from"@koishijs/client";import{defineComponent as I,openBlock as i,createElementBlock as r,Fragment as B,renderList as L,normalizeClass as M,createElementVNode as t,toDisplayString as c,createCommentVNode as k,createVNode as m,resolveComponent as U,withCtx as C,createTextVNode as h,createBlock as K,computed as E,ref as A,watch as ie,withKeys as ce,renderSlot as ve,reactive as te,unref as $}from"vue";const fe={class:"bw-step-indicator",role:"list"},be=["aria-current","onClick"],me={class:"bw-step-mark"},pe={class:"bw-step-label"},ge={key:0,class:"bw-step-rule","aria-hidden":"true"},ke=I({__name:"StepIndicator",props:{steps:{},stepStates:{}},emits:["go"],setup(e){return(l,n)=>(i(),r("ol",fe,[(i(true),r(B,null,L(e.steps,(s,a)=>(i(),r("li",{key:s.key,class:M(["bw-step",e.stepStates[s.key]])},[t("button",{type:"button",class:"bw-step-btn","aria-current":e.stepStates[s.key]==="current"?"step":void 0,onClick:p=>l.$emit("go",s.key)},[t("span",me,c(e.stepStates[s.key]==="done"?"✓":a+1),1),t("span",pe,c(s.label),1)],8,be),a<e.steps.length-1?(i(),r("span",ge)):k("v-if",true)],2))),128))]))}}),ye={class:"bw-header"},we={class:"bw-header-row"},he={class:"bw-header-title"},$e={class:"bw-header-meta bw-status-line"},Ce={class:"dot"},je={class:"dot"},xe={class:"dot"},Se={key:0,class:"dot is-danger"},Ve={key:1,class:"dot is-warn"},Oe=I({__name:"WorkbenchHeader",props:{steps:{},stepStates:{},currentStep:{},draft:{},packageNameOk:{type:Boolean},memberCount:{},errorCount:{},warningCount:{}},emits:["go"],setup(e){return(l,n)=>(i(),r("header",ye,[t("div",we,[t("div",he,[t("h1",null,c(e.currentStep.label),1),t("p",null,c(e.currentStep.description),1)]),t("div",$e,[t("span",{class:M(["bw-pkg-name",{"is-warn":!e.packageNameOk}])},c(e.draft.packageName||"未填写包名"),3),t("span",Ce,c(e.draft.version||"0.0.0"),1),t("span",je,c(e.draft.distTag||"alpha"),1),t("span",xe,c(e.memberCount)+" 成员",1),e.errorCount?(i(),r("span",Se,c(e.errorCount)+" 错误",1)):e.warningCount?(i(),r("span",Ve,c(e.warningCount)+" 警告",1)):k("v-if",true)])]),n[1]||(n[1]=t("div",{class:"bw-header-rule"},null,-1)),m(ke,{steps:e.steps,"step-states":e.stepStates,onGo:n[0]||(n[0]=s=>l.$emit("go",s))},null,8,["steps","step-states"])]))}}),Re={class:"bw-footer"},Pe={class:"bw-footer-left"},Ne={class:"bw-footer-hint"},Ee={class:"bw-footer-right"},ze=I({__name:"WorkbenchFooter",props:{primaryActionKind:{},primaryDisabled:{type:Boolean},blockReason:{},footerHint:{},isFirst:{type:Boolean},isLast:{type:Boolean},busyValidate:{type:Boolean},busyGenerate:{type:Boolean}},emits:["prev","next","validate","generate"],setup(e){return(l,n)=>{const s=U("el-button");return i(),r("footer",Re,[t("div",Pe,[m(s,{disabled:e.isFirst,onClick:n[0]||(n[0]=a=>l.$emit("prev"))},{default:C(()=>[...n[4]||(n[4]=[h("上一步",-1)])]),_:1},8,["disabled"])]),t("div",Ne,[t("span",{class:M(e.blockReason?"is-warn":"is-muted")},c(e.footerHint),3)]),t("div",Ee,[e.primaryActionKind==="next"?(i(),K(s,{key:0,type:"primary",disabled:e.primaryDisabled||e.isLast,onClick:n[1]||(n[1]=a=>l.$emit("next"))},{default:C(()=>[...n[5]||(n[5]=[h("下一步",-1)])]),_:1},8,["disabled"])):e.primaryActionKind==="validate"?(i(),K(s,{key:1,type:"primary",loading:e.busyValidate,onClick:n[2]||(n[2]=a=>l.$emit("validate"))},{default:C(()=>[...n[6]||(n[6]=[h("运行校验",-1)])]),_:1},8,["loading"])):(i(),K(s,{key:2,type:"primary",loading:e.busyGenerate,onClick:n[3]||(n[3]=a=>l.$emit("generate"))},{default:C(()=>[...n[7]||(n[7]=[h("生成文件",-1)])]),_:1},8,["loading"]))])])}}}),Ue={class:"bw-card"},Ae={class:"bw-form-grid"},Te={class:"bw-span-2"},Ke={class:"bw-span-2"},Be={class:"bw-span-2"},Ie={key:0,class:"bw-form-error is-danger"},Le=I({__name:"ProjectStep",props:{api:{}},setup(e){return(l,n)=>{const s=U("el-input");return i(),r("section",Ue,[n[15]||(n[15]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"项目基础信息"),t("p",null,[h("真实 npm 包名必须是小写的 "),t("code",null,"koishi-plugin-pa-*"),h(" 或 "),t("code",null,"@scope/koishi-plugin-pa-*"),h("。")])])],-1)),t("div",Ae,[t("label",null,[n[7]||(n[7]=t("span",null,"包名",-1)),m(s,{modelValue:e.api.draft.packageName,"onUpdate:modelValue":n[0]||(n[0]=a=>e.api.draft.packageName=a),placeholder:"koishi-plugin-pa-demo"},null,8,["modelValue"])]),t("label",null,[n[8]||(n[8]=t("span",null,"版本",-1)),m(s,{modelValue:e.api.draft.version,"onUpdate:modelValue":n[1]||(n[1]=a=>e.api.draft.version=a),placeholder:"0.1.0-alpha.0"},null,8,["modelValue"])]),t("label",null,[n[9]||(n[9]=t("span",null,"显示名称",-1)),m(s,{modelValue:e.api.draft.label,"onUpdate:modelValue":n[2]||(n[2]=a=>e.api.draft.label=a),placeholder:"Dialogue 插件包"},null,8,["modelValue"])]),t("label",null,[n[10]||(n[10]=t("span",null,"dist-tag",-1)),m(s,{modelValue:e.api.draft.distTag,"onUpdate:modelValue":n[3]||(n[3]=a=>e.api.draft.distTag=a),placeholder:"alpha"},null,8,["modelValue"])]),t("label",Te,[n[11]||(n[11]=t("span",null,"描述",-1)),m(s,{modelValue:e.api.draft.description,"onUpdate:modelValue":n[4]||(n[4]=a=>e.api.draft.description=a),type:"textarea",rows:3,placeholder:"说明这个插件包解决什么场景,包含哪些能力。"},null,8,["modelValue"])]),t("label",Ke,[n[12]||(n[12]=t("span",null,"Keywords (逗号分隔)",-1)),m(s,{modelValue:e.api.keywordsText.value,"onUpdate:modelValue":n[5]||(n[5]=a=>e.api.keywordsText.value=a),placeholder:"koishi, plugin, market:package"},null,8,["modelValue"])]),t("label",Be,[n[13]||(n[13]=t("span",null,"项目目录",-1)),m(s,{modelValue:e.api.projectPath.value,"onUpdate:modelValue":n[6]||(n[6]=a=>e.api.projectPath.value=a),placeholder:"相对 Koishi baseDir 或绝对路径"},null,8,["modelValue"])])]),e.api.packageNameOk.value?k("v-if",true):(i(),r("p",Ie,[...n[14]||(n[14]=[h(" 包名格式不合法,需要 ",-1),t("code",null,"koishi-plugin-pa-*",-1),h(" 或 ",-1),t("code",null,"@scope/koishi-plugin-pa-*",-1),h("。 ",-1)])])),n[16]||(n[16]=t("p",{class:"bw-form-note is-muted"},[h(" 工作台仅生成 "),t("code",null,"package.json"),h("、"),t("code",null,"README.md"),h(" 和 "),t("code",null,"lib/index.js"),h(";不会执行 npm publish。 ")],-1))])}}}),Me=/^@koishijs\/plugin-[0-9a-z-]+$|(^|\/)koishi-plugin-[0-9a-z-]+$/,De=/^(?:@[0-9a-z-]+\/)?koishi-plugin-pa-[0-9a-z-]+$/,Fe=/(command|script|exec|path|token|secret|password|sql|url|webhook|key)/i;function q(e=""){return e.trim().toLowerCase()}function H(e=""){return e.toLowerCase().replace(/(koishi-|^@koishijs\/)plugin-/,"")}function We(e=""){return Me.test(e)}function Je(e=""){return De.test(e.trim())}function Ge(e){return e?/^[0-9]+\.[0-9]+\.[0-9]+/.test(e)?`^${e}`:e:"^1.0.0"}function qe(){return Math.random().toString(36).slice(2,10)}function J(e){return!e||typeof e!="object"?{}:Object.fromEntries(Object.entries(e).filter(([l])=>!l.startsWith("$")).map(([l,n])=>Array.isArray(n)?[l,n.map(s=>oe(s))]:n&&typeof n=="object"?[l,J(n)]:[l,n]))}function oe(e){return Array.isArray(e)?e.map(l=>oe(l)):e&&typeof e=="object"?J(e):e}function re(e,l="",n=new Set){if(!e||typeof e!="object")return n;for(const[s,a]of Object.entries(e)){const p=l?`${l}.${s}`:s;Fe.test(s)&&n.add(p),a&&typeof a=="object"&&re(a,p,n)}return n}function ne(e,l){if(!(!e||typeof e!="object"))for(const n of Object.keys(e)){if(n.startsWith("$"))continue;const s=e[n],[a]=n.split(":",1);if(a.replace(/^~/,"")===l)return s;const f=ne(s,l);if(f)return f}}function He(e){return e.split(/[\s,,;;]+/g).map(l=>l.trim()).filter(Boolean)}const Ze={class:"bw-member-row"},Ye={class:"bw-tr bw-row-main"},Qe={class:"bw-cell-name"},Xe=["aria-expanded"],_e={class:"bw-name-block"},et={class:"is-muted"},tt={class:"bw-cell-version"},nt={class:"bw-cell-type"},at={class:"bw-cell-status bw-status-line"},st={key:0},lt={key:1},it={key:2,title:"该标记来自市场索引,不等于安全审计。"},ot={key:3,class:"is-danger"},rt={key:4,class:"is-danger"},ut={key:5,class:"is-accent"},dt={class:"bw-cell-actions"},ct={key:0,class:"bw-tr bw-row-detail"},vt={class:"bw-detail-grid"},ft=I({__name:"MemberRow",props:{member:{},isFirst:{type:Boolean},isLast:{type:Boolean},expanded:{type:Boolean},localVersion:{},hasSchema:{type:Boolean},hasPreset:{type:Boolean},market:{}},emits:["toggle","move","remove","updatePackage","updatePluginKey"],setup(e){const l=e,n=E(()=>H(l.member.package));return(s,a)=>{var w,N,j;const p=U("el-input"),f=U("el-option"),b=U("el-select"),O=U("el-button");return i(),r("div",Ze,[t("div",Ye,[t("div",Qe,[t("button",{type:"button",class:"bw-expander","aria-expanded":e.expanded,onClick:a[0]||(a[0]=R=>s.$emit("toggle"))},c(e.expanded?"▾":"▸"),9,Xe),t("div",_e,[t("strong",null,c(n.value||"未命名"),1),t("span",et,c(e.member.package||"等待输入包名"),1)])]),t("div",tt,[m(p,{modelValue:e.member.version,"onUpdate:modelValue":a[1]||(a[1]=R=>e.member.version=R),placeholder:"^1.0.0",size:"small"},null,8,["modelValue"])]),t("div",nt,[m(b,{modelValue:e.member.required,"onUpdate:modelValue":a[2]||(a[2]=R=>e.member.required=R),size:"small"},{default:C(()=>[m(f,{value:true,label:"required"}),m(f,{value:false,label:"optional"})]),_:1},8,["modelValue"])]),t("div",at,[e.localVersion?(i(),r("span",st,"local "+c(e.localVersion),1)):k("v-if",true),e.hasSchema?(i(),r("span",lt,"runtime schema")):k("v-if",true),(w=e.market)!=null&&w.verified?(i(),r("span",it,"市场认证")):k("v-if",true),(N=e.market)!=null&&N.insecure?(i(),r("span",ot,"风险标记")):k("v-if",true),(j=e.market)!=null&&j.deprecated?(i(),r("span",rt,"已废弃")):k("v-if",true),e.hasPreset?(i(),r("span",ut,"含预设配置")):k("v-if",true)]),t("div",dt,[m(O,{text:"",size:"small",disabled:e.isFirst,onClick:a[3]||(a[3]=R=>s.$emit("move",-1))},{default:C(()=>[...a[8]||(a[8]=[h("↑",-1)])]),_:1},8,["disabled"]),m(O,{text:"",size:"small",disabled:e.isLast,onClick:a[4]||(a[4]=R=>s.$emit("move",1))},{default:C(()=>[...a[9]||(a[9]=[h("↓",-1)])]),_:1},8,["disabled"]),m(O,{text:"",size:"small",type:"danger",onClick:a[5]||(a[5]=R=>s.$emit("remove"))},{default:C(()=>[...a[10]||(a[10]=[h("移除",-1)])]),_:1})])]),e.expanded?(i(),r("div",ct,[t("div",vt,[t("label",null,[a[11]||(a[11]=t("span",null,"完整包名",-1)),m(p,{"model-value":e.member.package,size:"small","onUpdate:modelValue":a[6]||(a[6]=R=>s.$emit("updatePackage",R))},null,8,["model-value"])]),t("label",null,[a[12]||(a[12]=t("span",null,"plugin 键",-1)),m(p,{"model-value":e.member.plugin,size:"small","onUpdate:modelValue":a[7]||(a[7]=R=>s.$emit("updatePluginKey",R))},null,8,["model-value"])])])])):k("v-if",true)])}}}),bt={class:"bw-card bw-add-card"},mt={class:"bw-installed-picker"},pt={class:"bw-installed-toolbar"},gt={class:"is-muted"},kt={class:"bw-installed-actions"},yt={key:0,class:"bw-installed-grid"},wt=["disabled","onClick"],ht={class:"bw-installed-check"},$t={class:"bw-installed-main"},Ct=["title"],jt=["title"],xt={class:"bw-installed-meta"},St={key:0},Vt={key:1,class:"ok"},Ot={key:2,class:"danger"},Rt={key:3,class:"danger"},Pt={key:1,class:"bw-empty compact"},Nt={class:"bw-add-grid"},Et={class:"bw-add-source"},zt={class:"bw-card"},Ut={class:"bw-card-head"},At={class:"is-muted"},Tt={key:0,class:"bw-empty"},Kt={key:1,class:"bw-table"},Bt=I({__name:"MembersStep",props:{api:{}},setup(e){const l=e,n=A([]),s=A(""),a=A(""),p=A(new Set),f=E(()=>new Set(n.value)),b=E(()=>l.api.installedOptions.value.filter(d=>!d.added).length),O=E(()=>{const d=s.value.trim().toLowerCase();return l.api.installedOptions.value.filter(o=>d?[o.name,o.shortname,o.version,o.description,o.category].some(x=>String(x??"").toLowerCase().includes(d)):true)}),w=E(()=>O.value.filter(d=>!d.added));ie(()=>l.api.installedOptions.value,d=>{const o=new Set(d.filter(x=>!x.added).map(x=>x.name));n.value=n.value.filter(x=>o.has(x))},{deep:true});function N(d){const o=new Set(p.value);o.has(d)?o.delete(d):o.add(d),p.value=o}function j(){n.value.length&&(l.api.addMembers(n.value),n.value=[])}function R(d){const o=l.api.installedOptions.value.find(z=>z.name===d);if(!o||o.added)return;const x=new Set(n.value);x.has(d)?x.delete(d):x.add(d),n.value=[...x]}function D(){const d=new Set(n.value);for(const o of w.value)d.add(o.name);n.value=[...d]}function F(){n.value=[]}function V(){l.api.addMember(a.value),a.value=""}function T(d,o){d.package=o,l.api.syncPluginKey(d)}return(d,o)=>{const x=U("el-input"),z=U("el-button");return i(),r(B,null,[t("section",bt,[o[8]||(o[8]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"添加成员"),t("p",null,"从已安装插件中选择,或手动输入 npm 包名。")])],-1)),t("div",mt,[t("div",pt,[t("div",null,[o[2]||(o[2]=t("span",{class:"bw-add-label"},"已安装插件",-1)),t("span",gt,"已选 "+c(n.value.length)+" / 可选 "+c(b.value),1)]),m(x,{modelValue:s.value,"onUpdate:modelValue":o[0]||(o[0]=y=>s.value=y),clearable:"",class:"bw-installed-search",placeholder:"搜索插件名、包名、描述或版本"},null,8,["modelValue"]),t("div",kt,[m(z,{size:"small",disabled:!w.value.length,onClick:D},{default:C(()=>[...o[3]||(o[3]=[h("全选当前",-1)])]),_:1},8,["disabled"]),m(z,{size:"small",disabled:!n.value.length,onClick:F},{default:C(()=>[...o[4]||(o[4]=[h("清空",-1)])]),_:1},8,["disabled"]),m(z,{type:"primary",size:"small",disabled:!n.value.length,onClick:j},{default:C(()=>[...o[5]||(o[5]=[h(" 加入已选 ",-1)])]),_:1},8,["disabled"])])]),O.value.length?(i(),r("div",yt,[(i(true),r(B,null,L(O.value,y=>(i(),r("button",{key:y.name,type:"button",class:M(["bw-installed-card",{selected:f.value.has(y.name),added:y.added,danger:y.insecure||y.deprecated}]),disabled:y.added,onClick:W=>R(y.name)},[t("span",ht,c(y.added?"已加入":f.value.has(y.name)?"已选":"可选"),1),t("span",$t,[t("strong",null,c(y.shortname),1),t("span",{class:"bw-installed-package",title:y.name},c(y.name),9,Ct),t("span",{class:"bw-installed-desc",title:y.description},c(y.description),9,jt)]),t("span",xt,[t("span",null,c(y.version),1),y.hasSchema?(i(),r("span",St,"schema")):k("v-if",true),y.verified?(i(),r("span",Vt,"市场认证")):k("v-if",true),y.insecure?(i(),r("span",Ot,"风险")):k("v-if",true),y.deprecated?(i(),r("span",Rt,"废弃")):k("v-if",true)])],10,wt))),128))])):(i(),r("div",Pt,c(e.api.installedOptions.value.length?"没有匹配的已安装插件。":"没有可选的已安装插件。"),1))]),t("div",Nt,[t("div",Et,[o[7]||(o[7]=t("span",{class:"bw-add-label is-muted"},"手动添加",-1)),m(x,{modelValue:a.value,"onUpdate:modelValue":o[1]||(o[1]=y=>a.value=y),placeholder:"koishi-plugin-example",onKeyup:ce(V,["enter"])},null,8,["modelValue"]),m(z,{type:"primary",plain:"",disabled:!a.value.trim(),onClick:V},{default:C(()=>[...o[6]||(o[6]=[h("添加",-1)])]),_:1},8,["disabled"])])])]),t("section",zt,[t("div",Ut,[t("div",null,[t("h2",null,[o[9]||(o[9]=h("成员列表 ",-1)),t("span",At,"("+c(e.api.members.length)+")",1)]),o[10]||(o[10]=t("p",null,"required 默认加入安装计划,optional 默认作为可选项展示。",-1))])]),e.api.members.length?(i(),r("div",Kt,[o[11]||(o[11]=t("div",{class:"bw-tr bw-th bw-row-main"},[t("div",null,"包名"),t("div",null,"版本范围"),t("div",null,"类型"),t("div",null,"状态"),t("div",null,"操作")],-1)),(i(true),r(B,null,L(e.api.members,(y,W)=>{var Q,u;return i(),K(ft,{key:y.id,member:y,"is-first":W===0,"is-last":W===e.api.members.length-1,expanded:p.value.has(y.id),"local-version":(u=(Q=e.api.packageInfo(y.package))==null?void 0:Q.package)==null?void 0:u.version,"has-schema":!!e.api.runtimeSchema(y),"has-preset":e.api.hasPresetConfig(y),market:e.api.marketInfo(y.package),onToggle:v=>N(y.id),onMove:v=>e.api.moveMember(W,v),onRemove:v=>e.api.removeMember(W),onUpdatePackage:v=>T(y,v),onUpdatePluginKey:v=>e.api.updatePluginKey(y,v)},null,8,["member","is-first","is-last","expanded","local-version","has-schema","has-preset","market","onToggle","onMove","onRemove","onUpdatePackage","onUpdatePluginKey"])}),128))])):(i(),r("div",Tt," 还没有添加成员。从上面的两种方式选择一个开始。 "))])],64)}}}),It={class:"bw-config-editor bw-card"},Lt={class:"bw-card-head"},Mt={class:"is-muted"},Dt={class:"bw-toolbar"},Ft={key:0,class:"bw-sensitive"},Wt={class:"is-muted"},Jt={class:"bw-tabs",role:"tablist"},Gt=["disabled","title"],qt={key:1,class:"bw-tab-body"},Ht={key:2,class:"bw-tab-body"},Zt={class:"bw-tab-actions"},Yt={key:0,class:"is-danger"},Qt={key:1,class:"is-muted"},Xt=I({__name:"ConfigEditor",props:{member:{},schema:{},sensitiveKeys:{}},emits:["copyExisting","reset","updateObject","syncFromText"],setup(e){const l=e,n=E(()=>!!l.schema),s=A(n.value?"form":"json");ie(n,f=>{!f&&s.value==="form"&&(s.value="json")});function a(f){f==="form"&&!n.value||(s.value=f)}const p=E(()=>H(l.member.package));return(f,b)=>{const O=U("el-button"),w=U("k-form"),N=U("el-input");return i(),r("article",It,[t("div",Lt,[t("div",null,[t("h3",null,c(p.value),1),t("p",Mt,c(e.member.package),1)]),t("div",Dt,[m(O,{size:"small",onClick:b[0]||(b[0]=j=>f.$emit("copyExisting"))},{default:C(()=>[...b[7]||(b[7]=[h("复制已有配置",-1)])]),_:1}),m(O,{size:"small",onClick:b[1]||(b[1]=j=>f.$emit("reset"))},{default:C(()=>[...b[8]||(b[8]=[h("清空",-1)])]),_:1})])]),e.sensitiveKeys.length?(i(),r("div",Ft,[b[9]||(b[9]=t("strong",{class:"is-warn"},"敏感字段",-1)),t("span",Wt,c(e.sensitiveKeys.join(", ")),1)])):k("v-if",true),t("div",Jt,[t("button",{type:"button",class:M({active:s.value==="form"}),disabled:!n.value,title:n.value?"":"未读取到 schema",role:"tab",onClick:b[2]||(b[2]=j=>a("form"))},"表单",10,Gt),t("button",{type:"button",class:M({active:s.value==="json"}),role:"tab",onClick:b[3]||(b[3]=j=>a("json"))},"JSON",2)]),s.value==="form"&&n.value?(i(),r("div",qt,[m(w,{schema:e.schema,initial:e.member.configObject,"model-value":e.member.configObject,"onUpdate:modelValue":b[4]||(b[4]=j=>f.$emit("updateObject",j))},null,8,["schema","initial","model-value"])])):(i(),r("div",Ht,[m(N,{modelValue:e.member.configText,"onUpdate:modelValue":b[5]||(b[5]=j=>e.member.configText=j),type:"textarea",rows:9,spellcheck:"false"},null,8,["modelValue"]),t("div",Zt,[m(O,{size:"small",onClick:b[6]||(b[6]=j=>f.$emit("syncFromText"))},{default:C(()=>[...b[10]||(b[10]=[h("解析 JSON",-1)])]),_:1}),e.member.configError?(i(),r("span",Yt,c(e.member.configError),1)):n.value?k("v-if",true):(i(),r("span",Qt,"该成员未读取到 schema,只能在 JSON 模式编辑。"))])]))])}}}),_t={class:"bw-card"},en={key:0,class:"bw-empty"},tn=I({__name:"ConfigStep",props:{api:{}},setup(e){return(l,n)=>(i(),r(B,null,[t("section",_t,[n[0]||(n[0]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"配置审计"),t("p",null,"预设配置会随插件包公开,敏感字段应在发布前逐项确认。")])],-1)),e.api.members.length?k("v-if",true):(i(),r("p",en,"先添加成员插件。"))]),(i(true),r(B,null,L(e.api.members,s=>(i(),K(Xt,{key:s.id,member:s,schema:e.api.runtimeSchema(s),"sensitive-keys":e.api.sensitiveKeys(s),onCopyExisting:a=>e.api.copyExistingConfig(s),onReset:a=>e.api.resetConfig(s),onUpdateObject:a=>e.api.updateConfigObject(s,a),onSyncFromText:a=>e.api.syncConfigText(s)},null,8,["member","schema","sensitive-keys","onCopyExisting","onReset","onUpdateObject","onSyncFromText"]))),128))],64))}}),nn={class:"bw-card"},an={class:"bw-card-head"},sn={class:"bw-toolbar"},ln={key:0,class:"bw-validate-grid"},on={class:"bw-validate-summary"},rn={class:"is-muted"},un={key:0,class:"bw-validate-npm"},dn={class:"is-muted"},cn={class:"bw-validate-issues"},vn={key:0,class:"is-muted"},fn={key:0,class:"bw-issue-path"},bn={key:1,class:"bw-empty"},mn=I({__name:"ValidateStep",props:{actions:{}},setup(e){return(l,n)=>{const s=U("el-button");return i(),r("section",nn,[t("div",an,[n[1]||(n[1]=t("div",null,[t("h2",null,"npm 与清单校验"),t("p",null,"检查包名、版本占用、成员包存在性、版本范围、自引用、重复成员和直接循环。")],-1)),t("div",sn,[m(s,{type:"primary",loading:e.actions.busy.validate,onClick:e.actions.validate},{default:C(()=>[...n[0]||(n[0]=[h(" 运行校验 ",-1)])]),_:1},8,["loading","onClick"])])]),e.actions.validation.value?(i(),r("div",ln,[t("div",on,[t("strong",{class:M(e.actions.validation.value.valid?"is-ok":"is-danger")},c(e.actions.validation.value.valid?"校验通过":"校验未通过"),3),t("span",rn,c(e.actions.errorCount.value)+" 个错误,"+c(e.actions.warningCount.value)+" 个警告 ",1)]),e.actions.npmEntries.value.length?(i(),r("div",un,[n[2]||(n[2]=t("h3",null,"npm 检查",-1)),(i(true),r(B,null,L(e.actions.npmEntries.value,a=>(i(),r("div",{key:a.name,class:"bw-validate-npm-item"},[t("div",null,[t("strong",null,c(a.name),1),t("span",dn,c(a.exists?`latest ${a.latest||"-"}`:a.error||"not found"),1)]),t("span",{class:M(a.exists?"is-ok":"is-danger")},c(a.exists?"存在":"缺失"),3)]))),128))])):k("v-if",true),t("div",cn,[n[3]||(n[3]=t("h3",null,"问题列表",-1)),e.actions.validation.value.issues.length?k("v-if",true):(i(),r("p",vn,"没有发现问题。")),(i(true),r(B,null,L(e.actions.validation.value.issues,(a,p)=>(i(),r("div",{key:p,class:M(["bw-issue",a.level])},[t("strong",null,c(a.level),1),t("span",null,[a.path?(i(),r("span",fn,c(a.path)+":",1)):k("v-if",true),h(c(a.message),1)])],2))),128))])])):(i(),r("p",bn,"点击运行校验后显示结果。"))])}}}),pn={key:0,class:"bw-result-panel"},gn={key:0,class:"bw-result-head"},kn={key:0,class:"is-muted"},ee=I({__name:"ResultPanel",props:{title:{},subtitle:{},status:{}},setup(e){return(l,n)=>e.title||l.$slots.default?(i(),r("section",pn,[e.title?(i(),r("div",gn,[t("strong",{class:M(e.status)},c(e.title),3),e.subtitle?(i(),r("span",kn,c(e.subtitle),1)):k("v-if",true)])):k("v-if",true),ve(l.$slots,"default")])):k("v-if",true)}}),yn={class:"bw-card"},wn={class:"bw-card-head"},hn={class:"bw-toolbar"},$n={class:"bw-download-grid"},Cn=["disabled"],jn={key:0,class:"bw-download-busy is-accent"},xn=["disabled"],Sn={key:0,class:"bw-download-busy is-accent"},Vn={key:0,class:"is-muted"},On={key:1,class:"bw-issue-warnings"},Rn={key:2,class:"bw-file-list"},Pn={key:0,class:"is-muted"},Nn={class:"bw-card"},En={class:"bw-write-controls bw-toolbar"},zn={class:"is-muted"},Un={class:"bw-checkbox-line"},An={class:"bw-file-list"},Tn={key:0,class:"is-warn"},Kn={key:1,class:"is-ok"},Bn={key:2,class:"is-muted"},In={key:0,class:"bw-pack-files"},Ln={key:0,class:"is-muted"},Mn={key:1,class:"bw-pre"},Dn={key:0,class:"bw-card"},Fn={class:"bw-pre"},Wn={class:"bw-pre"},Jn={class:"bw-pre"},Gn={class:"bw-pre"},qn={class:"bw-pre"},Hn=I({__name:"ReleaseStep",props:{actions:{},projectPath:{}},setup(e){const l=A(false),n=A("package");return(s,a)=>{const p=U("el-button"),f=U("el-checkbox"),b=U("el-tab-pane"),O=U("el-tabs");return i(),r(B,null,[t("section",yn,[t("div",wn,[a[8]||(a[8]=t("div",null,[t("h2",null,"下载与发布"),t("p",null,"下载 npm 发布包或源码 zip,使用本机 npm 登录态发布。")],-1)),t("div",hn,[m(p,{loading:e.actions.busy.generate,onClick:e.actions.generate},{default:C(()=>[...a[6]||(a[6]=[h("生成文件",-1)])]),_:1},8,["loading","onClick"]),m(p,{disabled:!e.actions.generated.value,onClick:e.actions.copyAll},{default:C(()=>[...a[7]||(a[7]=[h("复制全部输出",-1)])]),_:1},8,["disabled","onClick"])])]),t("div",$n,[t("button",{type:"button",class:"bw-download-card primary",disabled:e.actions.busy.archive==="npm-tgz",onClick:a[0]||(a[0]=w=>e.actions.downloadArchive("npm-tgz"))},[a[9]||(a[9]=t("span",{class:"bw-download-title"},"下载 npm 发布包",-1)),a[10]||(a[10]=t("span",{class:"bw-download-desc is-muted"},"真实 npm pack 产物,下载后可直接发布。",-1)),e.actions.busy.archive==="npm-tgz"?(i(),r("span",jn,"正在打包…")):k("v-if",true)],8,Cn),t("button",{type:"button",class:"bw-download-card",disabled:e.actions.busy.archive==="source-zip",onClick:a[1]||(a[1]=w=>e.actions.downloadArchive("source-zip"))},[a[11]||(a[11]=t("span",{class:"bw-download-title"},"下载源码 zip",-1)),a[12]||(a[12]=t("span",{class:"bw-download-desc is-muted"},"可审查的项目源码,自行解压发布。",-1)),e.actions.busy.archive==="source-zip"?(i(),r("span",Sn,"正在压缩…")):k("v-if",true)],8,xn)]),e.actions.archiveResult.value?(i(),K(ee,{key:0,title:e.actions.archiveResult.value.ok?"压缩包已生成":e.actions.archiveResult.value.error||"压缩包生成失败",status:e.actions.archiveResult.value.ok?"is-ok":"is-danger",subtitle:e.actions.archiveResult.value.filename?`文件:${e.actions.archiveResult.value.filename}`:void 0},{default:C(()=>{var w,N;return[e.actions.archiveResult.value.command?(i(),r("p",Vn,[a[13]||(a[13]=h(" 发布命令:",-1)),t("code",null,c(e.actions.archiveResult.value.command),1)])):k("v-if",true),(w=e.actions.archiveResult.value.warnings)!=null&&w.length?(i(),r("div",On,[(i(true),r(B,null,L(e.actions.archiveResult.value.warnings,(j,R)=>(i(),r("p",{key:R,class:"is-warn"},c(j.path?`${j.path}:`:"")+c(j.message),1))),128))])):k("v-if",true),(N=e.actions.archiveResult.value.files)!=null&&N.length?(i(),r("div",Rn,[(i(true),r(B,null,L(e.actions.archiveResult.value.files.slice(0,8),j=>(i(),r("p",{key:j.path},[t("code",null,c(j.path),1),j.size?(i(),r("span",Pn,c(j.size)+" bytes",1)):k("v-if",true)]))),128))])):k("v-if",true)]}),_:1},8,["title","status","subtitle"])):k("v-if",true)]),t("section",Nn,[a[20]||(a[20]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"写入项目"),t("p",null,"写入 ProjectStep 中填写的项目目录。预览模式不会修改磁盘。")])],-1)),t("div",En,[t("span",zn,[a[14]||(a[14]=h("目录:",-1)),t("code",null,c(e.projectPath||"未填写"),1)]),a[19]||(a[19]=t("span",{class:"bw-toolbar-spacer"},null,-1)),t("label",Un,[m(f,{modelValue:l.value,"onUpdate:modelValue":a[2]||(a[2]=w=>l.value=w)},null,8,["modelValue"]),a[15]||(a[15]=t("span",{class:"is-muted"},"允许覆盖",-1))]),m(p,{loading:e.actions.busy.previewWrite,disabled:!e.actions.generated.value||!e.projectPath,onClick:a[3]||(a[3]=w=>e.actions.previewWrite(l.value))},{default:C(()=>[...a[16]||(a[16]=[h("预览",-1)])]),_:1},8,["loading","disabled"]),m(p,{type:"primary",loading:e.actions.busy.write,disabled:!e.actions.generated.value||!e.projectPath,onClick:a[4]||(a[4]=w=>e.actions.writeToDisk(l.value))},{default:C(()=>[...a[17]||(a[17]=[h("写入项目",-1)])]),_:1},8,["loading","disabled"]),m(p,{loading:e.actions.busy.pack,disabled:!e.projectPath,onClick:e.actions.packDryRun},{default:C(()=>[...a[18]||(a[18]=[h(" npm pack --dry-run ",-1)])]),_:1},8,["loading","disabled","onClick"])]),e.actions.writeResult.value?(i(),K(ee,{key:0,title:e.actions.writeResult.value.ok?"文件检查通过":e.actions.writeResult.value.error||"仍有文件被跳过或写入失败",status:e.actions.writeResult.value.ok?"is-ok":"is-warn",subtitle:e.actions.writeResult.value.root?`目标:${e.actions.writeResult.value.root}`:void 0},{default:C(()=>[t("div",An,[(i(true),r(B,null,L(e.actions.writeResult.value.files,w=>(i(),r("p",{key:w.path},[t("code",null,c(w.path),1),w.skipped?(i(),r("span",Tn,"已存在,未覆盖")):w.written?(i(),r("span",Kn,"已写入")):(i(),r("span",Bn,"将写入"))]))),128))])]),_:1},8,["title","status","subtitle"])):k("v-if",true),e.actions.packResult.value?(i(),K(ee,{key:1,title:e.actions.packResult.value.ok?"dry-run 通过":e.actions.packResult.value.error||"dry-run 失败",status:e.actions.packResult.value.ok?"is-ok":"is-danger"},{default:C(()=>{var w;return[(w=e.actions.packResult.value.files)!=null&&w.length?(i(),r("ul",In,[(i(true),r(B,null,L(e.actions.packResult.value.files.slice(0,12),N=>(i(),r("li",{key:N.path},[t("code",null,c(N.path),1),N.size?(i(),r("span",Ln,c(N.size)+" bytes",1)):k("v-if",true)]))),128))])):k("v-if",true),e.actions.packResult.value.stderr?(i(),r("pre",Mn,c(e.actions.packResult.value.stderr),1)):k("v-if",true)]}),_:1},8,["title","status"])):k("v-if",true)]),e.actions.generated.value?(i(),r("section",Dn,[a[21]||(a[21]=t("div",{class:"bw-card-head"},[t("div",null,[t("h2",null,"生成内容预览"),t("p",null,"核对每个文件的内容,确认无误后再下载或写入。")])],-1)),m(O,{modelValue:n.value,"onUpdate:modelValue":a[5]||(a[5]=w=>n.value=w),class:"bw-output-tabs"},{default:C(()=>[m(b,{label:"package.json",name:"package"},{default:C(()=>[t("pre",Fn,c(e.actions.generated.value.packageJson),1)]),_:1}),m(b,{label:"koishi.bundle",name:"bundle"},{default:C(()=>[t("pre",Wn,c(e.actions.generated.value.bundleJson),1)]),_:1}),m(b,{label:"lib/index.js",name:"lib"},{default:C(()=>[t("pre",Jn,c(e.actions.generated.value.libIndex),1)]),_:1}),m(b,{label:"README",name:"readme"},{default:C(()=>[t("pre",Gn,c(e.actions.generated.value.readme),1)]),_:1}),m(b,{label:"发布命令",name:"commands"},{default:C(()=>[t("pre",qn,c(e.actions.generated.value.publishCommands.join(`
2
+ `)),1)]),_:1})]),_:1},8,["modelValue"])])):k("v-if",true)],64)}}});function ae(){return _.packages??{}}function se(){var e;return((e=_.market)==null?void 0:e.data)??{}}function le(e){if(typeof e=="string")return e.trim();if(!e||typeof e!="object")return"";const l=e;for(const s of["zh-CN","zh","en-US","en"]){const a=l[s];if(typeof a=="string"&&a.trim())return a.trim()}const n=Object.values(l).find(s=>typeof s=="string"&&s.trim());return typeof n=="string"?n.trim():""}function Zn(){const e=te({packageName:"koishi-plugin-pa-demo",version:"0.1.0-alpha.0",label:"",description:"",distTag:"alpha"}),l=te([]),n=A("koishi, plugin, market:package"),s=A(""),a=E(()=>Je(e.packageName)),p=E(()=>l.filter(N).length),f=E(()=>Object.values(ae()).filter(u=>{var v;return We((v=u==null?void 0:u.package)==null?void 0:v.name)}).map(u=>{var Y,X;const v=q(u.package.name),g=se()[v],P=u.package.version||"",Z=H(v);return{name:v,shortname:Z,version:P,label:`${Z} · ${v}@${P}`,description:le((Y=g==null?void 0:g.manifest)==null?void 0:Y.description)||le(u.package.description)||"没有本地描述。",hasSchema:!!((X=u.runtime)!=null&&X.schema),added:l.some(ue=>ue.package===v),verified:!!(g!=null&&g.verified),insecure:!!(g!=null&&g.insecure),deprecated:!!(g!=null&&g.deprecated),category:g==null?void 0:g.category}}).sort((u,v)=>u.shortname.localeCompare(v.shortname)));function b(u){return ae()[q(u)]}function O(u){return se()[q(u)]}function w(u){var v,g;return(g=(v=b(u.package))==null?void 0:v.runtime)==null?void 0:g.schema}function N(u){return!!u.configObject&&Object.keys(u.configObject).length>0}function j(u){return[...re(u.configObject)].slice(0,8)}function R(u,v,g=false){var Z,Y;const P=q(u);return P?l.some(X=>X.package===P)?(g||S.warning("这个成员已经在列表中。"),false):(l.push({id:qe(),package:P,plugin:H(P),version:Ge(v??((Y=(Z=b(P))==null?void 0:Z.package)==null?void 0:Y.version)),required:true,configText:"{}",configObject:{},autoPlugin:true}),true):false}function D(u){let v=0,g=0;for(const P of[...new Set(u.map(q).filter(Boolean))])R(P,void 0,true)?v+=1:g+=1;v?S.success(`已加入 ${v} 个成员。`):g&&S.warning("选择的插件都已经在成员列表中。")}function F(u){l.splice(u,1)}function V(u,v){const g=u+v;if(g<0||g>=l.length)return;const[P]=l.splice(u,1);l.splice(g,0,P)}function T(u){(u.autoPlugin||!u.plugin)&&(u.plugin=H(u.package),u.autoPlugin=true)}function d(u,v){u.plugin=v,u.autoPlugin=v===H(u.package)}function o(u,v){u.configObject=J(v),u.configText=JSON.stringify(u.configObject,null,2),u.configError=""}function x(u){o(u,{})}function z(u,v){u.configObject=J(v),u.configText=JSON.stringify(u.configObject,null,2),u.configError=""}function y(u){try{const v=JSON.parse(u.configText||"{}");return!v||typeof v!="object"||Array.isArray(v)?(u.configError="预设配置必须是对象。",false):(u.configObject=J(v),u.configText=JSON.stringify(u.configObject,null,2),u.configError="",S.success("已从 JSON 更新表单。"),true)}catch(v){return u.configError=v instanceof Error?v.message:String(v),false}}function W(u){var P;const v=(P=_.config)==null?void 0:P.plugins,g=ne(v,u.plugin)??ne(v,u.package);if(!g){S.warning("没有找到已有配置。");return}o(u,J(g))}function Q(){const u={...e,keywords:He(n.value),members:[]};for(const[v,g]of l.entries()){let P;try{P=JSON.parse(g.configText||"{}")}catch{S.error(`第 ${v+1} 个成员的预设配置不是合法 JSON。`);return}if(!P||typeof P!="object"||Array.isArray(P)){S.error(`第 ${v+1} 个成员的预设配置必须是对象。`);return}g.configObject=J(P),g.configError="",u.members.push({package:q(g.package),plugin:g.plugin.trim().toLowerCase(),version:g.version.trim(),required:g.required,config:P})}return u}return{draft:e,members:l,keywordsText:n,projectPath:s,packageNameOk:a,presetCount:p,installedOptions:f,packageInfo:b,marketInfo:O,runtimeSchema:w,hasPresetConfig:N,sensitiveKeys:j,addMember:R,addMembers:D,removeMember:F,moveMember:V,syncPluginKey:T,updatePluginKey:d,setConfig:o,resetConfig:x,updateConfigObject:z,syncConfigText:y,copyExistingConfig:W,buildPayload:Q}}function Yn(e){const l=A(),n=A(),s=A(),a=A(),p=A(),f=te({validate:false,generate:false,pack:false,previewWrite:false,write:false,archive:""}),b=E(()=>{var d;return((d=l.value)==null?void 0:d.issues.filter(o=>o.level==="error").length)??0}),O=E(()=>{var d;return((d=l.value)==null?void 0:d.issues.filter(o=>o.level==="warning").length)??0}),w=E(()=>{var d;return Object.values(((d=l.value)==null?void 0:d.npm)??{})});async function N(){const d=e.buildPayload();if(d){f.validate=true;try{l.value=await G("bundle-workbench/validate",d),l.value.valid?S.success("校验通过。"):S.warning("校验完成,仍有问题需要处理。")}catch(o){console.error(o),S.error("校验失败。")}finally{f.validate=false}}}async function j(){const d=e.buildPayload();if(d){f.generate=true;try{n.value=await G("bundle-workbench/generate",d),S.success("已生成插件包文件内容。")}catch(o){console.error(o),S.error("生成失败。")}finally{f.generate=false}}}async function R(d){const o=e.buildPayload();if(o){f.previewWrite=true;try{s.value=await G("bundle-workbench/write-files",e.projectPath.value,o,{dryRun:true,overwrite:d}),s.value.ok?S.success("写入预览通过。"):S.warning(s.value.error||"写入预览完成,有文件会被跳过。")}catch(x){console.error(x),S.error("写入预览失败。")}finally{f.previewWrite=false}}}async function D(d){const o=e.buildPayload();if(o){f.write=true;try{s.value=await G("bundle-workbench/write-files",e.projectPath.value,o,{overwrite:d}),s.value.ok?S.success("已写入插件包项目。"):S.warning(s.value.error||"部分文件被跳过,开启覆盖后可重试。")}catch(x){console.error(x),S.error("写入失败。")}finally{f.write=false}}}async function F(){f.pack=true;try{a.value=await G("bundle-workbench/pack-dry-run",e.projectPath.value),a.value.ok?S.success("dry-run 通过。"):S.error("dry-run 失败。")}catch(d){console.error(d),S.error("dry-run 调用失败。")}finally{f.pack=false}}async function V(d){var x;const o=e.buildPayload();if(o){f.archive=d;try{p.value=await G("bundle-workbench/download-archive",o,d);const z=p.value;if(!z.ok||!z.base64||!z.filename){S.error(z.error||"压缩包生成失败。");return}Qn(z.base64,z.filename,z.mime),(x=z.warnings)!=null&&x.length?S.warning(`已下载,但仍有 ${z.warnings.length} 个警告需要留意。`):S.success("压缩包已下载。")}catch(z){console.error(z),S.error("压缩包生成失败。")}finally{f.archive=""}}}async function T(){var o;if(!n.value)return;const d=["--- package.json ---",n.value.packageJson,"--- koishi.bundle ---",n.value.bundleJson,"--- lib/index.js ---",n.value.libIndex,"--- README.md ---",n.value.readme,"--- commands ---",n.value.publishCommands.join(`
3
3
  `)].join(`
4
4
 
5
- `);await((g=navigator.clipboard)==null?void 0:g.writeText(m)),x.success("已复制生成结果。")}return{validation:s,generated:n,writeResult:l,packResult:a,archiveResult:p,busy:d,errorCount:u,warningCount:S,npmEntries:k,validate:c,generate:j,previewWrite:R,writeToDisk:D,packDryRun:L,downloadArchive:f,copyAll:E}}function Nn(e,s,n="application/octet-stream"){const l=atob(e),a=new Uint8Array(l.length);for(let u=0;u<l.length;u++)a[u]=l.charCodeAt(u);const p=URL.createObjectURL(new Blob([a],{type:n})),d=document.createElement("a");d.href=p,d.download=s,document.body.appendChild(d),d.click(),d.remove(),URL.revokeObjectURL(p)}function zn(e){const s=[{key:"project",label:"项目",description:"定义插件包 npm 信息、关键词、dist-tag 和本地项目目录。",blockReason:()=>e.packageNameOk.value?null:"包名格式不合法,需要 koishi-plugin-pa-*"},{key:"members",label:"成员",description:"选择要打包的成员插件,声明版本范围、插件键和 required/optional。",blockReason:()=>e.members.length?null:"至少添加一个成员插件"},{key:"config",label:"配置",description:"审查每个成员的预设配置,检查敏感字段。"},{key:"validate",label:"校验",description:"通过 npm 和清单规则检查插件包是否可以安全发布。"},{key:"release",label:"发布",description:"下载 npm 发布包或源码 zip,也可以写入本地项目后 dry-run。"}],n=T("project");function l(f){return s.findIndex(E=>E.key===f)}const a=N(()=>s[l(n.value)]??s[0]),p=N(()=>{const f=n.value,E=l(f),m={project:"pending",members:"pending",config:"pending",validate:"pending",release:"pending"};for(const g of s){const O=l(g.key);if(g.key===f){m[g.key]="current";continue}g.key==="project"?e.packageNameOk.value?m[g.key]="done":O<E&&(m[g.key]="error"):g.key==="members"?e.members.length?m[g.key]="done":O<E&&(m[g.key]="error"):g.key==="config"?O<E&&(m[g.key]="done"):g.key==="validate"?e.validation.value&&(m[g.key]=e.errorCount.value===0?"done":"error"):g.key==="release"&&e.generated.value&&(m[g.key]="done")}return m}),d=N(()=>n.value==="validate"?"validate":n.value==="release"?"generate":"next"),u=N(()=>{var f,E;return((E=(f=a.value).blockReason)==null?void 0:E.call(f))??null}),S=N(()=>d.value==="next"?u.value!==null:false),k=N(()=>{if(u.value)return u.value;if(n.value==="validate")return e.validation.value?e.errorCount.value===0?"校验通过,可以进入下一步。":`仍有 ${e.errorCount.value} 个错误需要处理。`:"点击运行校验。";if(n.value==="release")return e.generated.value?"生成完毕,可下载或写入项目。":"可直接下载,或先生成文件。";const f=s[l(n.value)+1];return f?`下一步:${f.description}`:""});function c(){const f=l(n.value);f<s.length-1&&(n.value=s[f+1].key)}function j(){const f=l(n.value);f>0&&(n.value=s[f-1].key)}function R(f){n.value=f}const D=N(()=>l(n.value)===0),L=N(()=>l(n.value)===s.length-1);return{steps:s,activeStep:n,currentStep:a,stepStates:p,primaryActionKind:d,primaryDisabled:S,blockReason:u,footerHint:k,isFirst:D,isLast:L,next:c,prev:j,go:R}}const An={class:"bw-shell"},Tn={class:"bw-main"},Un=B({__name:"workbench",setup(e){const s=Pn(),n=En({buildPayload:s.buildPayload,projectPath:s.projectPath}),l=zn({packageNameOk:s.packageNameOk,members:s.members,errorCount:n.errorCount,validation:n.validation,generated:n.generated});return(a,p)=>{const d=P("k-layout");return i(),z(d,{main:"bundle-workbench"},{default:C(()=>[t("div",An,[b(Ce,{steps:h(l).steps,"step-states":h(l).stepStates.value,"current-step":h(l).currentStep.value,draft:h(s).draft,"package-name-ok":h(s).packageNameOk.value,"member-count":h(s).members.length,"error-count":h(n).errorCount.value,"warning-count":h(n).warningCount.value,onGo:h(l).go},null,8,["steps","step-states","current-step","draft","package-name-ok","member-count","error-count","warning-count","onGo"]),t("main",Tn,[h(l).activeStep.value==="project"?(i(),z(Te,{key:0,api:h(s)},null,8,["api"])):h(l).activeStep.value==="members"?(i(),z(pt,{key:1,api:h(s)},null,8,["api"])):h(l).activeStep.value==="config"?(i(),z(Tt,{key:2,api:h(s)},null,8,["api"])):h(l).activeStep.value==="validate"?(i(),z(Ht,{key:3,actions:h(n)},null,8,["actions"])):h(l).activeStep.value==="release"?(i(),z(Sn,{key:4,actions:h(n),"project-path":h(s).projectPath.value},null,8,["actions","project-path"])):w("v-if",true)]),b(Se,{"primary-action-kind":h(l).primaryActionKind.value,"primary-disabled":h(l).primaryDisabled.value,"block-reason":h(l).blockReason.value,"footer-hint":h(l).footerHint.value,"is-first":h(l).isFirst.value,"is-last":h(l).isLast.value,"busy-validate":h(n).busy.validate,"busy-generate":h(n).busy.generate,onPrev:h(l).prev,onNext:h(l).next,onValidate:h(n).validate,onGenerate:h(n).generate},null,8,["primary-action-kind","primary-disabled","block-reason","footer-hint","is-first","is-last","busy-validate","busy-generate","onPrev","onNext","onValidate","onGenerate"])])]),_:1})}}}),Kn=(e,s)=>{const n=e.__vccOpts||e;for(const[l,a]of s)n[l]=a;return n},Bn={},In={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512","aria-hidden":"true"};function Mn(e,s){return i(),o("svg",In,[...s[0]||(s[0]=[t("path",{fill:"currentColor",d:"M128 72c0-22.1 17.9-40 40-40h112c81.7 0 148 66.3 148 148 0 55.5-30.5 103.8-75.7 129.1l65.2 106.2c11.6 18.8-3.6 42.7-25.6 42.7h-43.8c-13.9 0-26.8-7.2-34.1-19l-61-99h-41v78c0 22.1-17.9 40-40 40h-4c-22.1 0-40-17.9-40-40V72Zm84 76v116h68c32 0 58-26 58-58s-26-58-58-58h-68Z"},null,-1)])])}const Dn=Kn(Bn,[["render",Mn]]);le.register("activity:bundle-workbench",Dn);function Ln(e){let s;function n(l){if(!(!l||typeof l!="object"))for(const a of Object.keys(l)){if(a.startsWith("$"))continue;const p=l[a];if(!p||typeof p!="object")continue;const d=a.startsWith("~"),S=(d?a.slice(1):a).split(":",1)[0];if(S==="market-bundle-workbench"||S==="koishi-plugin-market-bundle-workbench"){if(!d)return p;s||(s=p)}const k=n(p);if(k)return k}}return n(e)??s}function Wn(){var e,s;return((s=Ln((e=q.config)==null?void 0:e.plugins))==null?void 0:s.enableWorkbench)===true}const Gn=e=>{e.page({id:"bundle-workbench",path:"/bundle-workbench",name:"插件包工作台",icon:"activity:bundle-workbench",order:760,authority:4,fields:["config","packages"],disabled:()=>!Wn(),component:Un})};export{Gn as default,Wn as isWorkbenchEnabled};
5
+ `);await((o=navigator.clipboard)==null?void 0:o.writeText(d)),S.success("已复制生成结果。")}return{validation:l,generated:n,writeResult:s,packResult:a,archiveResult:p,busy:f,errorCount:b,warningCount:O,npmEntries:w,validate:N,generate:j,previewWrite:R,writeToDisk:D,packDryRun:F,downloadArchive:V,copyAll:T}}function Qn(e,l,n="application/octet-stream"){const s=atob(e),a=new Uint8Array(s.length);for(let b=0;b<s.length;b++)a[b]=s.charCodeAt(b);const p=URL.createObjectURL(new Blob([a],{type:n})),f=document.createElement("a");f.href=p,f.download=l,document.body.appendChild(f),f.click(),f.remove(),URL.revokeObjectURL(p)}function Xn(e){const l=[{key:"project",label:"项目",description:"定义插件包 npm 信息、关键词、dist-tag 和本地项目目录。",blockReason:()=>e.packageNameOk.value?null:"包名格式不合法,需要 koishi-plugin-pa-*"},{key:"members",label:"成员",description:"选择要打包的成员插件,声明版本范围、插件键和 required/optional。",blockReason:()=>e.members.length?null:"至少添加一个成员插件"},{key:"config",label:"配置",description:"审查每个成员的预设配置,检查敏感字段。"},{key:"validate",label:"校验",description:"通过 npm 和清单规则检查插件包是否可以安全发布。"},{key:"release",label:"发布",description:"下载 npm 发布包或源码 zip,也可以写入本地项目后 dry-run。"}],n=A("project");function s(V){return l.findIndex(T=>T.key===V)}const a=E(()=>l[s(n.value)]??l[0]),p=E(()=>{const V=n.value,T=s(V),d={project:"pending",members:"pending",config:"pending",validate:"pending",release:"pending"};for(const o of l){const x=s(o.key);if(o.key===V){d[o.key]="current";continue}o.key==="project"?e.packageNameOk.value?d[o.key]="done":x<T&&(d[o.key]="error"):o.key==="members"?e.members.length?d[o.key]="done":x<T&&(d[o.key]="error"):o.key==="config"?x<T&&(d[o.key]="done"):o.key==="validate"?e.validation.value&&(d[o.key]=e.errorCount.value===0?"done":"error"):o.key==="release"&&e.generated.value&&(d[o.key]="done")}return d}),f=E(()=>n.value==="validate"?"validate":n.value==="release"?"generate":"next"),b=E(()=>{var V,T;return((T=(V=a.value).blockReason)==null?void 0:T.call(V))??null}),O=E(()=>f.value==="next"?b.value!==null:false),w=E(()=>{if(b.value)return b.value;if(n.value==="validate")return e.validation.value?e.errorCount.value===0?"校验通过,可以进入下一步。":`仍有 ${e.errorCount.value} 个错误需要处理。`:"点击运行校验。";if(n.value==="release")return e.generated.value?"生成完毕,可下载或写入项目。":"可直接下载,或先生成文件。";const V=l[s(n.value)+1];return V?`下一步:${V.description}`:""});function N(){const V=s(n.value);V<l.length-1&&(n.value=l[V+1].key)}function j(){const V=s(n.value);V>0&&(n.value=l[V-1].key)}function R(V){n.value=V}const D=E(()=>s(n.value)===0),F=E(()=>s(n.value)===l.length-1);return{steps:l,activeStep:n,currentStep:a,stepStates:p,primaryActionKind:f,primaryDisabled:O,blockReason:b,footerHint:w,isFirst:D,isLast:F,next:N,prev:j,go:R}}const _n={class:"bw-shell"},ea={class:"bw-main"},ta=I({__name:"workbench",setup(e){const l=Zn(),n=Yn({buildPayload:l.buildPayload,projectPath:l.projectPath}),s=Xn({packageNameOk:l.packageNameOk,members:l.members,errorCount:n.errorCount,validation:n.validation,generated:n.generated});return(a,p)=>{const f=U("k-layout");return i(),K(f,{main:"bundle-workbench"},{default:C(()=>[t("div",_n,[m(Oe,{steps:$(s).steps,"step-states":$(s).stepStates.value,"current-step":$(s).currentStep.value,draft:$(l).draft,"package-name-ok":$(l).packageNameOk.value,"member-count":$(l).members.length,"error-count":$(n).errorCount.value,"warning-count":$(n).warningCount.value,onGo:$(s).go},null,8,["steps","step-states","current-step","draft","package-name-ok","member-count","error-count","warning-count","onGo"]),t("main",ea,[$(s).activeStep.value==="project"?(i(),K(Le,{key:0,api:$(l)},null,8,["api"])):$(s).activeStep.value==="members"?(i(),K(Bt,{key:1,api:$(l)},null,8,["api"])):$(s).activeStep.value==="config"?(i(),K(tn,{key:2,api:$(l)},null,8,["api"])):$(s).activeStep.value==="validate"?(i(),K(mn,{key:3,actions:$(n)},null,8,["actions"])):$(s).activeStep.value==="release"?(i(),K(Hn,{key:4,actions:$(n),"project-path":$(l).projectPath.value},null,8,["actions","project-path"])):k("v-if",true)]),m(ze,{"primary-action-kind":$(s).primaryActionKind.value,"primary-disabled":$(s).primaryDisabled.value,"block-reason":$(s).blockReason.value,"footer-hint":$(s).footerHint.value,"is-first":$(s).isFirst.value,"is-last":$(s).isLast.value,"busy-validate":$(n).busy.validate,"busy-generate":$(n).busy.generate,onPrev:$(s).prev,onNext:$(s).next,onValidate:$(n).validate,onGenerate:$(n).generate},null,8,["primary-action-kind","primary-disabled","block-reason","footer-hint","is-first","is-last","busy-validate","busy-generate","onPrev","onNext","onValidate","onGenerate"])])]),_:1})}}}),na=(e,l)=>{const n=e.__vccOpts||e;for(const[s,a]of l)n[s]=a;return n},aa={},sa={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512","aria-hidden":"true"};function la(e,l){return i(),r("svg",sa,[...l[0]||(l[0]=[t("path",{fill:"currentColor",d:"M128 72c0-22.1 17.9-40 40-40h112c81.7 0 148 66.3 148 148 0 55.5-30.5 103.8-75.7 129.1l65.2 106.2c11.6 18.8-3.6 42.7-25.6 42.7h-43.8c-13.9 0-26.8-7.2-34.1-19l-61-99h-41v78c0 22.1-17.9 40-40 40h-4c-22.1 0-40-17.9-40-40V72Zm84 76v116h68c32 0 58-26 58-58s-26-58-58-58h-68Z"},null,-1)])])}const ia=na(aa,[["render",la]]);de.register("activity:bundle-workbench",ia);function oa(e){let l;function n(s){if(!(!s||typeof s!="object"))for(const a of Object.keys(s)){if(a.startsWith("$"))continue;const p=s[a];if(!p||typeof p!="object")continue;const f=a.startsWith("~"),O=(f?a.slice(1):a).split(":",1)[0];if(O==="market-bundle-workbench"||O==="koishi-plugin-market-bundle-workbench"){if(!f)return p;l||(l=p)}const w=n(p);if(w)return w}}return n(e)??l}function ra(){var e,l;return((l=oa((e=_.config)==null?void 0:e.plugins))==null?void 0:l.enableWorkbench)===true}const ca=e=>{e.page({id:"bundle-workbench",path:"/bundle-workbench",name:"插件包工作台",icon:"activity:bundle-workbench",order:760,authority:4,fields:["config","packages"],disabled:()=>!ra(),component:ta})};export{ca as default,ra as isWorkbenchEnabled};
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.bw-step-indicator{display:flex;align-items:center;gap:0;margin:0;padding:0;list-style:none;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}.bw-step{display:flex;align-items:center;flex:0 0 auto}.bw-step:last-child{flex:0 1 auto}.bw-step-btn{display:inline-flex;align-items:center;gap:.45rem;border:0;background:transparent;padding:.3rem .5rem;color:var(--fg2);font-size:.86rem;cursor:pointer;border-radius:var(--bw-radius-sm)}.bw-step-btn:hover{color:var(--fg1);background:color-mix(in srgb,var(--k-color-primary) 6%,transparent)}.bw-step-mark{display:inline-grid;place-items:center;width:var(--bw-step-size);height:var(--bw-step-size);border-radius:999px;border:1px solid var(--fg3);color:var(--fg3);font-size:.78rem;font-weight:600;background:var(--k-card-bg)}.bw-step-label{font-weight:500}.bw-step-rule{display:inline-block;width:1.6rem;height:1px;margin:0 .25rem;background:var(--fg3);opacity:.6}.bw-step.current .bw-step-mark{border-color:var(--k-color-primary);color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 10%,var(--k-card-bg))}.bw-step.current .bw-step-label{color:var(--fg1);font-weight:600}.bw-step.done .bw-step-mark{border-color:var(--k-color-success);color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,var(--k-card-bg))}.bw-step.done .bw-step-label{color:var(--fg1)}.bw-step.error .bw-step-mark{border-color:var(--k-color-danger);color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,var(--k-card-bg))}.bw-step.error .bw-step-label{color:var(--k-color-danger)}@media (max-width: 720px){.bw-step-rule{width:.8rem}.bw-step-btn{padding:.2rem .35rem;font-size:.8rem}}.bw-header{flex:0 0 auto;padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-bottom:var(--bw-border)}.bw-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-lg);flex-wrap:wrap}.bw-header-title{min-width:0}.bw-header-title h1{margin:0;font-size:1.05rem;font-weight:600;color:var(--fg1)}.bw-header-title p{margin:.2rem 0 0;color:var(--fg3);font-size:.82rem;line-height:1.5;max-width:48rem}.bw-header-meta{font-size:.8rem}.bw-pkg-name{font-family:var(--bw-font-mono);color:var(--fg1);font-weight:500}.bw-header-rule{height:var(--bw-gap-md)}@media (max-width: 720px){.bw-header{padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-header-meta{width:100%}}.bw-footer{flex:0 0 auto;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-md);padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-top:var(--bw-border)}.bw-footer-hint{font-size:.85rem;text-align:center;min-width:0}.bw-footer-hint span{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.bw-footer-right{display:flex;justify-content:flex-end;gap:var(--bw-gap-sm)}@media (max-width: 720px){.bw-footer{grid-template-columns:1fr 1fr;grid-template-areas:"hint hint" "left right";padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-footer-hint{grid-area:hint;text-align:left}.bw-footer-left{grid-area:left}.bw-footer-right{grid-area:right}}.bw-form-error{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-error code{font-family:var(--bw-font-mono)}.bw-form-note{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-note code{font-family:var(--bw-font-mono)}.bw-member-row{display:contents}.bw-row-main{grid-template-columns:minmax(13rem,2.4fr) minmax(7rem,1fr) 7rem minmax(8rem,1.4fr) auto}.bw-row-main>div{min-width:0}.bw-cell-name{display:flex;align-items:center;gap:var(--bw-gap-sm);min-width:0}.bw-expander{flex:0 0 auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--fg3);font-size:.85rem;cursor:pointer;padding:0 .25rem;width:1.4rem}.bw-name-block{min-width:0;display:flex;flex-direction:column;gap:.1rem;overflow:hidden}.bw-name-block strong{color:var(--fg1);font-size:.9rem;font-weight:600}.bw-name-block span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;font-family:var(--bw-font-mono)}.bw-cell-status{font-size:.76rem;gap:var(--bw-gap-xs) var(--bw-gap-sm)}.bw-cell-actions{display:flex;gap:.15rem;white-space:nowrap}.bw-row-detail{background:var(--bw-bg-elev)}.bw-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-detail-grid label{display:grid;gap:.25rem}.bw-detail-grid label>span{color:var(--fg3);font-size:.78rem}@media (max-width: 820px){.bw-row-main{grid-template-columns:1fr auto;grid-template-areas:"name actions" "version type" "status status";row-gap:var(--bw-gap-xs)}.bw-cell-name{grid-area:name}.bw-cell-version{grid-area:version}.bw-cell-type{grid-area:type}.bw-cell-status{grid-area:status}.bw-cell-actions{grid-area:actions}.bw-detail-grid{grid-template-columns:1fr}}.bw-add-card{margin-bottom:var(--bw-gap-md)}.bw-add-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-add-source{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-add-label{font-size:.82rem;white-space:nowrap}@media (max-width: 820px){.bw-add-grid{grid-template-columns:1fr}.bw-add-source{grid-template-columns:minmax(0,1fr) auto}.bw-add-source .bw-add-label{grid-column:1/-1}.bw-row-main.bw-th{display:none}}.bw-config-editor+.bw-config-editor{margin-top:var(--bw-gap-md)}.bw-sensitive{display:flex;align-items:center;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md);padding:.45rem var(--bw-gap-md);border-radius:var(--bw-radius-sm);background:color-mix(in srgb,var(--k-color-warning) 8%,transparent);font-size:.82rem}.bw-sensitive strong{flex:0 0 auto}.bw-sensitive span{word-break:break-all}.bw-tab-body{display:grid;gap:var(--bw-gap-sm)}.bw-tab-actions{display:flex;align-items:center;gap:var(--bw-gap-sm);font-size:.82rem}.bw-validate-grid{display:grid;gap:var(--bw-gap-md)}.bw-validate-summary{display:flex;justify-content:space-between;gap:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-validate-summary strong{font-size:1rem}.bw-validate-summary span{font-size:.85rem}.bw-validate-npm,.bw-validate-issues{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-md)}.bw-validate-npm h3,.bw-validate-issues h3{margin:0 0 var(--bw-gap-sm);font-size:.88rem;color:var(--fg2)}.bw-validate-npm-item{display:flex;align-items:center;justify-content:space-between;gap:var(--bw-gap-md);padding:.35rem 0;border-bottom:var(--bw-border-soft)}.bw-validate-npm-item:last-child{border-bottom:0}.bw-validate-npm-item strong{font-family:var(--bw-font-mono);font-size:.85rem}.bw-validate-npm-item span{display:block;font-size:.78rem}.bw-issue{display:grid;grid-template-columns:4.5rem minmax(0,1fr);gap:var(--bw-gap-sm);padding:.3rem 0;font-size:.84rem;color:var(--fg2)}.bw-issue strong{text-transform:uppercase;font-size:.74rem;letter-spacing:.04em;align-self:center}.bw-issue.error strong,.bw-issue.error span{color:var(--k-color-danger)}.bw-issue.warning strong{color:var(--k-color-warning)}.bw-issue-path{font-family:var(--bw-font-mono);font-size:.78rem;color:var(--fg3);margin-right:.25rem}.bw-result-panel{display:grid;gap:var(--bw-gap-sm);margin-top:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-result-head{display:flex;align-items:baseline;gap:var(--bw-gap-md);flex-wrap:wrap}.bw-result-head strong{font-size:.94rem}.bw-result-head span{font-size:.82rem}.bw-download-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-download-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;gap:var(--bw-gap-xs);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--k-card-bg);cursor:pointer;text-align:left}.bw-download-card:hover:not(:disabled){border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-card:disabled{cursor:progress;opacity:.7}.bw-download-card.primary{border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-title{color:var(--fg1);font-size:.95rem;font-weight:600}.bw-download-desc{font-size:.8rem;line-height:1.5}.bw-download-busy{font-size:.78rem;margin-top:.2rem}.bw-write-controls{margin-top:var(--bw-gap-md);font-size:.85rem}.bw-write-controls .bw-toolbar-spacer{flex:1}.bw-checkbox-line{display:inline-flex;align-items:center;gap:.35rem}.bw-issue-warnings{display:grid;gap:.2rem}.bw-issue-warnings p{margin:0;font-size:.82rem}.bw-file-list{display:grid;gap:.2rem}.bw-file-list p{display:flex;justify-content:space-between;gap:var(--bw-gap-md);margin:0;font-size:.82rem;color:var(--fg2)}.bw-file-list code{font-family:var(--bw-font-mono)}.bw-pack-files{margin:.2rem 0 0;padding-left:1.2rem;font-size:.82rem;color:var(--fg2)}.bw-pack-files li{line-height:1.5}.bw-pack-files code{font-family:var(--bw-font-mono)}.bw-output-tabs{margin-top:var(--bw-gap-md)}@media (max-width: 720px){.bw-download-grid{grid-template-columns:1fr}}:root{--bw-gap-xs: .35rem;--bw-gap-sm: .5rem;--bw-gap-md: .75rem;--bw-gap-lg: 1rem;--bw-gap-xl: 1.4rem;--bw-radius: 6px;--bw-radius-sm: 4px;--bw-border: 1px solid color-mix(in srgb, var(--k-color-border) 70%, transparent);--bw-border-strong: 1px solid color-mix(in srgb, var(--k-color-border) 95%, transparent);--bw-border-soft: 1px solid color-mix(in srgb, var(--k-color-border) 45%, transparent);--bw-bg-soft: color-mix(in srgb, var(--k-card-bg) 88%, transparent);--bw-bg-elev: color-mix(in srgb, var(--k-side-bg) 60%, var(--k-card-bg));--bw-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bw-step-size: 1.4rem}.bw-shell{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;overflow:hidden;background:var(--k-side-bg)}.bw-shell code{font-family:var(--bw-font-mono)}.bw-main{flex:1 1 auto;min-height:0;overflow:auto;padding:var(--bw-gap-lg)}.bw-card{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-lg);background:var(--k-card-bg)}.bw-card+.bw-card{margin-top:var(--bw-gap-md)}.bw-card h2,.bw-card h3{margin:0;font-size:1rem}.bw-card>.bw-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-md);margin-bottom:var(--bw-gap-md)}.bw-card>.bw-card-head h2{font-size:1rem}.bw-card>.bw-card-head p{margin:.2rem 0 0;color:var(--fg3);font-size:.84rem;line-height:1.55}.bw-toolbar{display:flex;align-items:center;gap:var(--bw-gap-sm);flex-wrap:wrap}.bw-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-form-grid label{display:grid;gap:.32rem}.bw-form-grid label>span{color:var(--fg2);font-size:.82rem}.bw-form-grid .bw-span-2{grid-column:1/-1}.bw-status-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--bw-gap-xs) var(--bw-gap-md);color:var(--fg3);font-size:.8rem}.bw-status-line span.dot:before{content:"·";margin:0 .25rem}.is-ok{color:var(--k-color-success)!important}.is-warn{color:var(--k-color-warning)!important}.is-danger{color:var(--k-color-danger)!important}.is-muted{color:var(--fg3)!important}.is-accent{color:var(--k-color-primary)!important}.bw-table{display:grid;width:100%;border:var(--bw-border);border-radius:var(--bw-radius);overflow:hidden;background:var(--k-card-bg)}.bw-table .bw-tr{display:grid;align-items:center;gap:var(--bw-gap-sm);padding:.45rem var(--bw-gap-md);border-top:var(--bw-border-soft)}.bw-table .bw-tr:first-child{border-top:0}.bw-table .bw-tr.bw-th{background:var(--bw-bg-elev);color:var(--fg3);font-size:.78rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.bw-table .bw-tr.bw-row-detail{grid-template-columns:1fr;padding:var(--bw-gap-md);background:var(--bw-bg-elev);border-top:var(--bw-border-soft)}.bw-tabs{display:flex;gap:0;border-bottom:var(--bw-border-soft);margin-bottom:var(--bw-gap-md)}.bw-tabs button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;padding:.45rem .85rem;color:var(--fg2);font-size:.85rem;cursor:pointer;border-bottom:2px solid transparent}.bw-tabs button:hover{color:var(--fg1)}.bw-tabs button.active{color:var(--fg1);border-bottom-color:var(--k-color-primary)}.bw-tabs button:disabled{color:var(--fg3);cursor:not-allowed}.bw-empty{display:grid;place-items:center;gap:var(--bw-gap-xs);padding:var(--bw-gap-xl) var(--bw-gap-md);color:var(--fg3);text-align:center;font-size:.88rem}.bw-pre{max-height:28rem;margin:0;border-radius:var(--bw-radius-sm);padding:var(--bw-gap-md);overflow:auto;background:var(--k-color-code-bg, rgba(0, 0, 0, .08));font-family:var(--bw-font-mono);font-size:.78rem;line-height:1.5}@media (max-width: 720px){.bw-form-grid{grid-template-columns:1fr}}.bundle-workbench{display:flex;min-height:0;overflow:hidden}
1
+ @charset "UTF-8";.bw-step-indicator{display:flex;align-items:center;gap:0;margin:0;padding:0;list-style:none;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}.bw-step{display:flex;align-items:center;flex:0 0 auto}.bw-step:last-child{flex:0 1 auto}.bw-step-btn{display:inline-flex;align-items:center;gap:.45rem;border:0;background:transparent;padding:.3rem .5rem;color:var(--fg2);font-size:.86rem;cursor:pointer;border-radius:var(--bw-radius-sm)}.bw-step-btn:hover{color:var(--fg1);background:color-mix(in srgb,var(--k-color-primary) 6%,transparent)}.bw-step-mark{display:inline-grid;place-items:center;width:var(--bw-step-size);height:var(--bw-step-size);border-radius:999px;border:1px solid var(--fg3);color:var(--fg3);font-size:.78rem;font-weight:600;background:var(--k-card-bg)}.bw-step-label{font-weight:500}.bw-step-rule{display:inline-block;width:1.6rem;height:1px;margin:0 .25rem;background:var(--fg3);opacity:.6}.bw-step.current .bw-step-mark{border-color:var(--k-color-primary);color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 10%,var(--k-card-bg))}.bw-step.current .bw-step-label{color:var(--fg1);font-weight:600}.bw-step.done .bw-step-mark{border-color:var(--k-color-success);color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,var(--k-card-bg))}.bw-step.done .bw-step-label{color:var(--fg1)}.bw-step.error .bw-step-mark{border-color:var(--k-color-danger);color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,var(--k-card-bg))}.bw-step.error .bw-step-label{color:var(--k-color-danger)}@media (max-width: 720px){.bw-step-rule{width:.8rem}.bw-step-btn{padding:.2rem .35rem;font-size:.8rem}}.bw-header{flex:0 0 auto;padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-bottom:var(--bw-border)}.bw-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-lg);flex-wrap:wrap}.bw-header-title{min-width:0}.bw-header-title h1{margin:0;font-size:1.05rem;font-weight:600;color:var(--fg1)}.bw-header-title p{margin:.2rem 0 0;color:var(--fg3);font-size:.82rem;line-height:1.5;max-width:48rem}.bw-header-meta{font-size:.8rem}.bw-pkg-name{font-family:var(--bw-font-mono);color:var(--fg1);font-weight:500}.bw-header-rule{height:var(--bw-gap-md)}@media (max-width: 720px){.bw-header{padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-header-meta{width:100%}}.bw-footer{flex:0 0 auto;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-md);padding:var(--bw-gap-md) var(--bw-gap-lg);background:var(--bw-bg-soft);border-top:var(--bw-border)}.bw-footer-hint{font-size:.85rem;text-align:center;min-width:0}.bw-footer-hint span{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.bw-footer-right{display:flex;justify-content:flex-end;gap:var(--bw-gap-sm)}@media (max-width: 720px){.bw-footer{grid-template-columns:1fr 1fr;grid-template-areas:"hint hint" "left right";padding:var(--bw-gap-sm) var(--bw-gap-md)}.bw-footer-hint{grid-area:hint;text-align:left}.bw-footer-left{grid-area:left}.bw-footer-right{grid-area:right}}.bw-form-error{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-error code{font-family:var(--bw-font-mono)}.bw-form-note{margin:var(--bw-gap-md) 0 0;font-size:.82rem}.bw-form-note code{font-family:var(--bw-font-mono)}.bw-member-row{display:contents}.bw-row-main{grid-template-columns:minmax(13rem,2.4fr) minmax(7rem,1fr) 7rem minmax(8rem,1.4fr) auto}.bw-row-main>div{min-width:0}.bw-cell-name{display:flex;align-items:center;gap:var(--bw-gap-sm);min-width:0}.bw-expander{flex:0 0 auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--fg3);font-size:.85rem;cursor:pointer;padding:0 .25rem;width:1.4rem}.bw-name-block{min-width:0;display:flex;flex-direction:column;gap:.1rem;overflow:hidden}.bw-name-block strong{color:var(--fg1);font-size:.9rem;font-weight:600}.bw-name-block span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;font-family:var(--bw-font-mono)}.bw-cell-status{font-size:.76rem;gap:var(--bw-gap-xs) var(--bw-gap-sm)}.bw-cell-actions{display:flex;gap:.15rem;white-space:nowrap}.bw-row-detail{background:var(--bw-bg-elev)}.bw-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-detail-grid label{display:grid;gap:.25rem}.bw-detail-grid label>span{color:var(--fg3);font-size:.78rem}@media (max-width: 820px){.bw-row-main{grid-template-columns:1fr auto;grid-template-areas:"name actions" "version type" "status status";row-gap:var(--bw-gap-xs)}.bw-cell-name{grid-area:name}.bw-cell-version{grid-area:version}.bw-cell-type{grid-area:type}.bw-cell-status{grid-area:status}.bw-cell-actions{grid-area:actions}.bw-detail-grid{grid-template-columns:1fr}}.bw-add-card{margin-bottom:var(--bw-gap-md)}.bw-installed-picker{display:grid;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md)}.bw-installed-toolbar{display:grid;grid-template-columns:auto minmax(16rem,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-installed-toolbar>div:first-child{display:grid;gap:.08rem}.bw-installed-search{min-width:0}.bw-installed-actions{display:flex;align-items:center;gap:var(--bw-gap-xs)}.bw-installed-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(16.5rem,1fr));gap:var(--bw-gap-sm);max-height:20rem;overflow:auto;padding:2px}.bw-installed-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;grid-template-columns:auto minmax(0,1fr);gap:.42rem .58rem;align-items:start;min-width:0;border:var(--bw-border);border-radius:var(--bw-radius-sm);padding:.54rem .62rem;color:var(--fg1);background:var(--k-card-bg);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,box-shadow .15s}.bw-installed-card:hover,.bw-installed-card:focus-visible{border-color:color-mix(in srgb,var(--k-color-primary) 42%,var(--k-color-border));outline:none}.bw-installed-card.selected{border-color:color-mix(in srgb,var(--k-color-primary) 62%,var(--k-color-border));background:linear-gradient(90deg,color-mix(in srgb,var(--k-color-primary) 10%,transparent),transparent 55%),var(--k-card-bg);box-shadow:inset 3px 0 0 var(--k-color-primary)}.bw-installed-card.danger{border-color:color-mix(in srgb,var(--k-color-danger) 32%,var(--k-color-border))}.bw-installed-card.added{cursor:default;opacity:.58;background:color-mix(in srgb,var(--k-side-bg) 72%,transparent)}.bw-installed-check{grid-row:1/span 2;display:inline-flex;align-items:center;justify-content:center;min-width:2.6rem;height:1.35rem;border-radius:999px;color:var(--fg2);background:color-mix(in srgb,var(--fg3) 10%,transparent);font-size:.72rem;font-weight:600}.bw-installed-card.selected .bw-installed-check{color:var(--k-color-primary);background:color-mix(in srgb,var(--k-color-primary) 12%,transparent)}.bw-installed-main{min-width:0;display:grid;gap:.12rem}.bw-installed-main strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.88rem}.bw-installed-package,.bw-installed-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bw-installed-package{color:var(--fg3);font-family:var(--bw-font-mono);font-size:.72rem}.bw-installed-desc{color:var(--fg2);font-size:.75rem}.bw-installed-meta{grid-column:2;display:flex;flex-wrap:wrap;gap:.24rem}.bw-installed-meta span{border-radius:4px;padding:.04rem .34rem;color:var(--fg3);background:color-mix(in srgb,var(--fg3) 9%,transparent);font-size:.68rem}.bw-installed-meta span.ok{color:var(--k-color-success);background:color-mix(in srgb,var(--k-color-success) 10%,transparent)}.bw-installed-meta span.danger{color:var(--k-color-danger);background:color-mix(in srgb,var(--k-color-danger) 10%,transparent)}.bw-add-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--bw-gap-md)}.bw-add-source{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--bw-gap-sm)}.bw-add-label{font-size:.82rem;white-space:nowrap}@media (max-width: 820px){.bw-installed-toolbar{grid-template-columns:1fr;align-items:stretch}.bw-installed-actions{justify-content:flex-end;flex-wrap:wrap}.bw-installed-grid{grid-template-columns:1fr;max-height:18rem}.bw-add-source{grid-template-columns:minmax(0,1fr) auto}.bw-add-source .bw-add-label{grid-column:1/-1}.bw-row-main.bw-th{display:none}}.bw-config-editor+.bw-config-editor{margin-top:var(--bw-gap-md)}.bw-sensitive{display:flex;align-items:center;gap:var(--bw-gap-sm);margin-bottom:var(--bw-gap-md);padding:.45rem var(--bw-gap-md);border-radius:var(--bw-radius-sm);background:color-mix(in srgb,var(--k-color-warning) 8%,transparent);font-size:.82rem}.bw-sensitive strong{flex:0 0 auto}.bw-sensitive span{word-break:break-all}.bw-tab-body{display:grid;gap:var(--bw-gap-sm)}.bw-tab-actions{display:flex;align-items:center;gap:var(--bw-gap-sm);font-size:.82rem}.bw-validate-grid{display:grid;gap:var(--bw-gap-md)}.bw-validate-summary{display:flex;justify-content:space-between;gap:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-validate-summary strong{font-size:1rem}.bw-validate-summary span{font-size:.85rem}.bw-validate-npm,.bw-validate-issues{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-md)}.bw-validate-npm h3,.bw-validate-issues h3{margin:0 0 var(--bw-gap-sm);font-size:.88rem;color:var(--fg2)}.bw-validate-npm-item{display:flex;align-items:center;justify-content:space-between;gap:var(--bw-gap-md);padding:.35rem 0;border-bottom:var(--bw-border-soft)}.bw-validate-npm-item:last-child{border-bottom:0}.bw-validate-npm-item strong{font-family:var(--bw-font-mono);font-size:.85rem}.bw-validate-npm-item span{display:block;font-size:.78rem}.bw-issue{display:grid;grid-template-columns:4.5rem minmax(0,1fr);gap:var(--bw-gap-sm);padding:.3rem 0;font-size:.84rem;color:var(--fg2)}.bw-issue strong{text-transform:uppercase;font-size:.74rem;letter-spacing:.04em;align-self:center}.bw-issue.error strong,.bw-issue.error span{color:var(--k-color-danger)}.bw-issue.warning strong{color:var(--k-color-warning)}.bw-issue-path{font-family:var(--bw-font-mono);font-size:.78rem;color:var(--fg3);margin-right:.25rem}.bw-result-panel{display:grid;gap:var(--bw-gap-sm);margin-top:var(--bw-gap-md);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--bw-bg-elev)}.bw-result-head{display:flex;align-items:baseline;gap:var(--bw-gap-md);flex-wrap:wrap}.bw-result-head strong{font-size:.94rem}.bw-result-head span{font-size:.82rem}.bw-download-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-download-card{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:grid;gap:var(--bw-gap-xs);padding:var(--bw-gap-md);border:var(--bw-border);border-radius:var(--bw-radius);background:var(--k-card-bg);cursor:pointer;text-align:left}.bw-download-card:hover:not(:disabled){border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-card:disabled{cursor:progress;opacity:.7}.bw-download-card.primary{border-color:color-mix(in srgb,var(--k-color-primary) 35%,var(--k-color-border))}.bw-download-title{color:var(--fg1);font-size:.95rem;font-weight:600}.bw-download-desc{font-size:.8rem;line-height:1.5}.bw-download-busy{font-size:.78rem;margin-top:.2rem}.bw-write-controls{margin-top:var(--bw-gap-md);font-size:.85rem}.bw-write-controls .bw-toolbar-spacer{flex:1}.bw-checkbox-line{display:inline-flex;align-items:center;gap:.35rem}.bw-issue-warnings{display:grid;gap:.2rem}.bw-issue-warnings p{margin:0;font-size:.82rem}.bw-file-list{display:grid;gap:.2rem}.bw-file-list p{display:flex;justify-content:space-between;gap:var(--bw-gap-md);margin:0;font-size:.82rem;color:var(--fg2)}.bw-file-list code{font-family:var(--bw-font-mono)}.bw-pack-files{margin:.2rem 0 0;padding-left:1.2rem;font-size:.82rem;color:var(--fg2)}.bw-pack-files li{line-height:1.5}.bw-pack-files code{font-family:var(--bw-font-mono)}.bw-output-tabs{margin-top:var(--bw-gap-md)}@media (max-width: 720px){.bw-download-grid{grid-template-columns:1fr}}:root{--bw-gap-xs: .35rem;--bw-gap-sm: .5rem;--bw-gap-md: .75rem;--bw-gap-lg: 1rem;--bw-gap-xl: 1.4rem;--bw-radius: 6px;--bw-radius-sm: 4px;--bw-border: 1px solid color-mix(in srgb, var(--k-color-border) 70%, transparent);--bw-border-strong: 1px solid color-mix(in srgb, var(--k-color-border) 95%, transparent);--bw-border-soft: 1px solid color-mix(in srgb, var(--k-color-border) 45%, transparent);--bw-bg-soft: color-mix(in srgb, var(--k-card-bg) 88%, transparent);--bw-bg-elev: color-mix(in srgb, var(--k-side-bg) 60%, var(--k-card-bg));--bw-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bw-step-size: 1.4rem}.bw-shell{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;overflow:hidden;background:var(--k-side-bg)}.bw-shell code{font-family:var(--bw-font-mono)}.bw-main{flex:1 1 auto;min-height:0;overflow:auto;padding:var(--bw-gap-lg)}.bw-card{border:var(--bw-border);border-radius:var(--bw-radius);padding:var(--bw-gap-lg);background:var(--k-card-bg)}.bw-card+.bw-card{margin-top:var(--bw-gap-md)}.bw-card h2,.bw-card h3{margin:0;font-size:1rem}.bw-card>.bw-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--bw-gap-md);margin-bottom:var(--bw-gap-md)}.bw-card>.bw-card-head h2{font-size:1rem}.bw-card>.bw-card-head p{margin:.2rem 0 0;color:var(--fg3);font-size:.84rem;line-height:1.55}.bw-toolbar{display:flex;align-items:center;gap:var(--bw-gap-sm);flex-wrap:wrap}.bw-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--bw-gap-md)}.bw-form-grid label{display:grid;gap:.32rem}.bw-form-grid label>span{color:var(--fg2);font-size:.82rem}.bw-form-grid .bw-span-2{grid-column:1/-1}.bw-status-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--bw-gap-xs) var(--bw-gap-md);color:var(--fg3);font-size:.8rem}.bw-status-line span.dot:before{content:"·";margin:0 .25rem}.is-ok{color:var(--k-color-success)!important}.is-warn{color:var(--k-color-warning)!important}.is-danger{color:var(--k-color-danger)!important}.is-muted{color:var(--fg3)!important}.is-accent{color:var(--k-color-primary)!important}.bw-table{display:grid;width:100%;border:var(--bw-border);border-radius:var(--bw-radius);overflow:hidden;background:var(--k-card-bg)}.bw-table .bw-tr{display:grid;align-items:center;gap:var(--bw-gap-sm);padding:.45rem var(--bw-gap-md);border-top:var(--bw-border-soft)}.bw-table .bw-tr:first-child{border-top:0}.bw-table .bw-tr.bw-th{background:var(--bw-bg-elev);color:var(--fg3);font-size:.78rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.bw-table .bw-tr.bw-row-detail{grid-template-columns:1fr;padding:var(--bw-gap-md);background:var(--bw-bg-elev);border-top:var(--bw-border-soft)}.bw-tabs{display:flex;gap:0;border-bottom:var(--bw-border-soft);margin-bottom:var(--bw-gap-md)}.bw-tabs button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;padding:.45rem .85rem;color:var(--fg2);font-size:.85rem;cursor:pointer;border-bottom:2px solid transparent}.bw-tabs button:hover{color:var(--fg1)}.bw-tabs button.active{color:var(--fg1);border-bottom-color:var(--k-color-primary)}.bw-tabs button:disabled{color:var(--fg3);cursor:not-allowed}.bw-empty{display:grid;place-items:center;gap:var(--bw-gap-xs);padding:var(--bw-gap-xl) var(--bw-gap-md);color:var(--fg3);text-align:center;font-size:.88rem}.bw-pre{max-height:28rem;margin:0;border-radius:var(--bw-radius-sm);padding:var(--bw-gap-md);overflow:auto;background:var(--k-color-code-bg, rgba(0, 0, 0, .08));font-family:var(--bw-font-mono);font-size:.78rem;line-height:1.5}@media (max-width: 720px){.bw-form-grid{grid-template-columns:1fr}}.bundle-workbench{display:flex;min-height:0;overflow:hidden}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-market-bundle-workbench",
3
- "version": "0.2.0-alpha.0",
3
+ "version": "0.2.0-alpha.2",
4
4
  "description": "Plugin bundle authoring workbench for Koishi Market NEXT.",
5
5
  "homepage": "https://github.com/qinfeng365/koishi-plugin-market-bundle-workbench#readme",
6
6
  "repository": {