@kanyun-ai-infra/band-cli 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/bundled/examples/aitutor-tool/band/views/release/package.json +1 -1
  2. package/bundled/examples/aitutor-tool/band/views/tool-preview/package.json +1 -1
  3. package/bundled/examples/analysis/band/views/intake/package.json +1 -1
  4. package/bundled/examples/compliance/band/views/compliance/package.json +1 -1
  5. package/bundled/examples/content-review/band/views/checklist/package.json +1 -1
  6. package/bundled/examples/rush-site/band/views/rush-db/package.json +1 -1
  7. package/bundled/examples/rush-site/band/views/rush-deploy/package.json +1 -1
  8. package/bundled/examples/video/band/views/timeline/package.json +1 -1
  9. package/bundled/kernel/fixture.js +1 -1
  10. package/bundled/kernel/index.js +1 -1
  11. package/bundled/official/activity/package.json +4 -4
  12. package/bundled/official/approval/package.json +4 -4
  13. package/bundled/official/artifacts/package.json +4 -4
  14. package/bundled/official/chat/dist/index.js +1 -1
  15. package/bundled/official/chat/package.json +4 -4
  16. package/bundled/official/chunks/chunk-7XYETT7C.js +1 -0
  17. package/bundled/official/comment/dist/index.js +1 -1
  18. package/bundled/official/comment/package.json +4 -4
  19. package/bundled/official/header/package.json +4 -4
  20. package/bundled/official/home/dist/index.js +1 -1
  21. package/bundled/official/home/package.json +4 -4
  22. package/bundled/official/layouts/package.json +4 -4
  23. package/bundled/official/library/dist/index.js +1 -1
  24. package/bundled/official/library/package.json +4 -4
  25. package/bundled/official/members/dist/index.js +1 -1
  26. package/bundled/official/members/package.json +4 -4
  27. package/bundled/official/memory/package.json +4 -4
  28. package/bundled/official/native/package.json +2 -2
  29. package/bundled/official/params-form/package.json +4 -4
  30. package/bundled/official/plugins/package.json +4 -4
  31. package/bundled/official/project/dist/index.js +1 -1
  32. package/bundled/official/project/package.json +4 -4
  33. package/bundled/official/queue/package.json +4 -4
  34. package/bundled/official/settings/dist/index.js +1 -1
  35. package/bundled/official/settings/package.json +4 -4
  36. package/bundled/official/shell/dist/index.js +1 -1
  37. package/bundled/official/shell/package.json +4 -4
  38. package/bundled/official/stages/package.json +4 -4
  39. package/bundled/official/threads/dist/index.js +1 -1
  40. package/bundled/official/threads/package.json +4 -4
  41. package/bundled/official/turn-bar/package.json +4 -4
  42. package/bundled/official/turn-trace/package.json +4 -4
  43. package/bundled/official/version-switch/dist/index.js +1 -1
  44. package/bundled/official/version-switch/package.json +4 -4
  45. package/bundled/official/viewer-entity/package.json +2 -2
  46. package/bundled/official/viewer-external/package.json +2 -2
  47. package/bundled/official/viewer-image/package.json +2 -2
  48. package/bundled/official/viewer-media/package.json +2 -2
  49. package/bundled/official/viewer-storyboard/package.json +2 -2
  50. package/bundled/official/viewer-text/package.json +4 -4
  51. package/bundled/official/viewer-tool/package.json +2 -2
  52. package/bundled/official/viewer-web/package.json +2 -2
  53. package/bundled/official/viewer-web-app/package.json +2 -2
  54. package/bundled/official/workshops/dist/index.js +2 -2
  55. package/bundled/official/workshops/package.json +4 -4
  56. package/bundled/official/workshops/plugin.yaml +2 -2
  57. package/bundled/skills/band-plugin/references/code.md +2 -2
  58. package/bundled/skills/band-plugin/references/manifest.md +2 -2
  59. package/bundled/skills/band-plugin/references/rules.md +1 -0
  60. package/bundled/skills/band-plugin/references/testing-publish.md +1 -1
  61. package/bundled/skills/band-plugin/templates/panel/package.json +1 -1
  62. package/bundled/tokens/components.css +1 -1
  63. package/dev-host/app.tsx +32 -12
  64. package/dev-host/host.css +7 -0
  65. package/dist/bin.js +3 -3
  66. package/dist/build-plugin.d.ts +1 -1
  67. package/dist/build-plugin.js +1 -1
  68. package/dist/{chunk-VTAJX7NN.js → chunk-FGPWXAOA.js} +165 -26
  69. package/dist/{chunk-TQHHHXXU.js → chunk-LGYGWMSY.js} +18 -16
  70. package/dist/{chunk-JWZU3NOD.js → chunk-XPLYTHNX.js} +1 -1
  71. package/dist/{dev-server-SB5FMSVP.js → dev-server-IBR3PKDE.js} +33 -5
  72. package/dist/fixture.d.ts +11 -0
  73. package/dist/index.d.ts +4 -2
  74. package/dist/index.js +3 -3
  75. package/dist/vite.d.ts +1 -1
  76. package/dist/vite.js +2 -2
  77. package/dist/{workshop-repo-Uq6blxyt.d.ts → workshop-repo-DqoVdcGu.d.ts} +9 -9
  78. package/package.json +10 -7
  79. package/src/dev-managers.ts +16 -0
  80. package/src/inspector-default.ts +9 -0
  81. package/bundled/official/chunks/chunk-SB74RUTN.js +0 -1
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@kanyun-ai-infra/band-workshops",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
4
4
  "description": "工坊目录、工坊详情、新建项目、新建与复制工坊、工坊设置与对话改工坊九个页面",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./dist/index.js"
8
8
  },
9
9
  "peerDependencies": {
10
- "@kanyun-ai-infra/band-plugin-sdk": "^1.222.0",
11
- "react": "^18.3.1",
12
- "react-dom": "^18.3.1",
10
+ "@kanyun-ai-infra/band-plugin-sdk": "^2.1.0",
11
+ "react": "^19.0.0",
12
+ "react-dom": "^19.0.0",
13
13
  "@kanyun-ai-infra/band-shell": "*"
14
14
  }
15
15
  }
@@ -1,4 +1,4 @@
1
- # 官方插件:工坊目录、工坊详情、新建项目、新建与复制工坊、工坊设置(v8 §7)。往外壳的 pages 贡献九页:/workshops 目录,
1
+ # 官方插件:工坊目录、工坊详情、新建项目、新建工坊与基于已有工坊新建、工坊设置(v8 §7)。往外壳的 pages 贡献九页:/workshops 目录,
2
2
  # /w/<工坊>/about 详情(工坊轻应用的「关于工坊」),/w/<工坊>/new 用这个工坊新建项目,/workshops/new 新建工坊,
3
3
  # /workshops/<工坊>/copy 复制这个工坊(不放在 /w/ 下:那一层的第二段是项目短名),/w/<工坊>/about/model 工坊设置 ·
4
4
  # 模型,/w/<工坊>/about/secrets 工坊设置 · 密钥,/w/<工坊>/new/resume 从「我的模型与凭据」配好回来后接着新建。旧地址写在 aliases,打开时改写成新地址。
@@ -39,7 +39,7 @@ contributes:
39
39
  - slot: "@kanyun-ai-infra/band-shell/pages"
40
40
  id: copy
41
41
  route: /workshops/:workshop/copy
42
- title: 复制工坊
42
+ title: 基于已有工坊新建
43
43
  frame: shell
44
44
  # 工坊设置 · 模型(建工坊的第 2 步也是这一页):/w/<工坊>/about/model,比 about 更具体;部署没开代建时页面写明没有这一步
45
45
  - slot: "@kanyun-ai-infra/band-shell/pages"
@@ -44,7 +44,7 @@ export default definePlugin({
44
44
 
45
45
  - `ctx.version`:`current()` 当前版本(可能是 null),`subscribe` 换版本,`list(artifactId)` 一份产物的全部版本(从旧到新),`readFile(path)`、`objectUrl(path)` 读当前版本的文件(可传 `{ versionId }` 读别的版本)。查看器的 `ctx.version` 钉在正在看的版本上,换版本时整个重挂。
46
46
  - `ctx.selection`:本项目里插件共享的选中,`get` / `set` / `subscribe`。五种:`{ kind: "artifact", artifactId }`、`{ kind: "entity", entityType, id, artifactId? }`、`{ kind: "timecode", seconds, end?, artifactId?, path? }`、`{ kind: "anchor", anchor }`、`{ kind: "stage", stage }`。`subscribe` 收到 `{ value, source }`,`source === ctx.plugin` 是自己的回声,跳过;不认识的 `kind` 当作与己无关。插件之间联动只靠它,不要互相 import 状态。
47
- - `ctx.anchors.make(kind, payload, snapshot?)`:在当前版本上造锚点。内置类型直接写;自己注册的写短名,内核补成 `plugin:<包名>/<kind>`。内置类型的 payload 都要带 `label`,内容在文件里的还要带 `path`,多写字段也算不合写法(1.x 只在控制台警告,2.0 起报错;`shot` 现在就抛错)。自己注册的类型也把 `label` 写进 payload:线程里显示的位置文字取它,`AnchorType.label` 现在没人调用。形状:`entity` 是 `{ path, label, entityType, id, hash?, point? }`,`text-range` 是 `{ path, label, quote: { exact, prefix?, suffix? }, pos?, lines? }`,`region` 是 `{ path, label, rect: { x, y, w, h }, page? }`(0–1 比例),`timecode` 是 `{ path, label, seconds, end?, rect? }`,`shot` 是 `{ path: "storyboard.json", label, shotId, takeId? }`。
47
+ - `ctx.anchors.make(kind, payload, snapshot?)`:在当前版本上造锚点。内置类型直接写;自己注册的写短名,内核补成 `plugin:<包名>/<kind>`。内置类型的 payload 都要带 `label`,内容在文件里的还要带 `path`,多写字段也算不合写法(当前只在控制台警告,以后的协议大版本会改成报错;`shot` 现在就抛错)。自己注册的类型也把 `label` 写进 payload:线程里显示的位置文字取它,`AnchorType.label` 现在没人调用。形状:`entity` 是 `{ path, label, entityType, id, hash?, point? }`,`text-range` 是 `{ path, label, quote: { exact, prefix?, suffix? }, pos?, lines? }`,`region` 是 `{ path, label, rect: { x, y, w, h }, page? }`(0–1 比例),`timecode` 是 `{ path, label, seconds, end?, rect? }`,`shot` 是 `{ path: "storyboard.json", label, shotId, takeId? }`。
48
48
  - `ctx.threads.list(filter)` 读线程;`ctx.threads.openAt(anchor, { draft, handToAgent, intent })` 请锁定的评论框在锚点上打开(`intent` 只有 `"pick"`:镜头候选上「用这条」,锚点是带 `takeId` 的 `shot`);`ctx.threads.open(id)` 打开已有线程。插件不能自己建线程。
49
49
  - 引用:`ctx.threads.quote(threadId, commentId)` 把一条消息、`ctx.threads.quoteAnchor(anchor)` 把一处位置作为引用放进发送框,都不发送。
50
50
  - `ctx.gate.open(stage, key?)` 请批准面板打开;`ctx.stages.list / get / start / rerun / rerunWith` 读写阶段运行。
@@ -55,4 +55,4 @@ export default definePlugin({
55
55
  - `ctx.events.subscribe("thread.*", fn)`:按类型或前缀订阅事件。事件名以 `EVENT_TYPES`(`@kanyun-ai-infra/band-plugin-sdk` 导出)为准;关心意见就订 `EVENT_GROUPS.threads`(含评论、改动请求、回合),关心流程就订 `EVENT_GROUPS.stages`,别只订 `thread.*`。
56
56
  - 打开停靠位:`(ctx.services.get("@kanyun-ai-infra/band-project/dock") as { open(key: string): void }).open("<包名>/<停靠位 id>")`。工具栏按钮写了 `dock` 的,查看器替你开。
57
57
  - `ctx.member`(`can("comment")` 判能不能提意见)、`ctx.params`、`ctx.plugin`(本插件的包名)。
58
- - 只给官方插件、工坊插件拿到 `undefined` 的:`notify`、`approvalSettings`、`memberSettings`、`visibilitySettings`、`artifactShares`、`version.archiveUrl`、`turns.requestStop`、`project.shared`、`project.notices`、`project.upgrade`、`project.remove`;`app.data.write.workshopArchive` 只给部署方案插件。不要写依赖它们的功能。
58
+ - 只给官方插件、工坊插件拿到 `undefined` 的:`notify`、`approvalSettings`、`memberSettings`、`visibilitySettings`、`artifactShares`、`version.archiveUrl`、`turns.requestStop`、`project.shared`、`project.notices`、`project.upgrade`、`project.remove`;`app.data.write.workshopArchive`、`people`(人员目录)只给部署方案插件。不要写依赖它们的功能。
@@ -13,7 +13,7 @@
13
13
  "keywords": ["数据库", "表格"],
14
14
  "type": "module",
15
15
  "peerDependencies": {
16
- "@kanyun-ai-infra/band-plugin-sdk": "^1.0.0",
16
+ "@kanyun-ai-infra/band-plugin-sdk": "^2.0.0",
17
17
  "@kanyun-ai-infra/band-project": "*",
18
18
  "@kanyun-ai-infra/band-viewer-web": "*"
19
19
  },
@@ -23,7 +23,7 @@
23
23
 
24
24
  - 包名带作用域,工坊插件用工坊名(`band new plugin` 取工坊仓库的目录名,去掉 `band-` 前缀);`@kanyun-ai-infra/band-` 前缀只留给官方插件。
25
25
  - `description`(一句话说明)与 `keywords` 显示在插件目录里,人和 Rondo 靠它们挑插件,写上。`"private": true` 表示只在本工坊用;工坊插件不发 npm 包。
26
- - `peerDependencies` 必须有 `@kanyun-ai-infra/band-plugin-sdk`(协议版本,`^1.0.0`)。往谁的插槽贡献、用谁的服务,就把谁写进来;官方插件还没有对外版本号,写 `"*"`。
26
+ - `peerDependencies` 必须有 `@kanyun-ai-infra/band-plugin-sdk`(协议版本,`^2.0.0`)。往谁的插槽贡献、用谁的服务,就把谁写进来;官方插件还没有对外版本号,写 `"*"`。
27
27
 
28
28
  `plugin.yaml`:Band 的声明,不写 `name`(顶层写了 `name` 的是已废弃的 0.x 清单,`band check` 直接报错)。
29
29
 
@@ -6,6 +6,7 @@
6
6
  - **异步要防乱序**:换版本、切环境时旧请求的结果可能晚到。每次加载记一个序号,结果回来时对不上就丢掉;读不到新数据时清空界面,不留旧数据(尤其是带「删除」按钮的表格)。
7
7
  - **读不到不抛错**:版本里可能没有你要的文件、JSON 可能坏了。界面显示「这个版本没有……」,锚点解析返回 null。
8
8
  - **路径参数要编码**:`ctx.resources.fetch` 的 path 里拼进去的 id 用 `encodeURIComponent`。
9
+ - **选人/选产物、标签、列表筛选、回执用现成组件**:`@kanyun-ai-infra/band-plugin-react` 导出 `Combobox`(可搜索单选/多选,受控 `items`/`value`/`onChange`,`label` 必写)、`TagInput`(字符串数组,回车或逗号确认、粘贴拆开、重复提示)、`FilterMenu` + `filterRows`(按几个单值维度筛,带计数)、`toast()`(一次性回执,只调不挂 `ToastHost`;失败用 `kind: "bad"` 带「重试」)。不要手写下拉搜索、标签输入、临时提示条。设置与表单里的保存反馈不弹 toast。详见用户文档「用 React 写插件」与 Band Design 站「组件」。
9
10
  - **样式只用 Band Design token**:页面提供 `--panel`、`--ink`、`--muted`、`--accent`、`--r-lg` 等 CSS 变量,插件里不写死颜色,类名带插件名前缀。琥珀色(`--warn*`)只给部署方案装的插件(锁定插件、应用级页面)用,工坊插件不用。
10
11
  - **工坊页面跟工坊最新发布走,项目页跟项目钉住的版本走**:同一工坊里两者可能是不同版本的插件代码。页面里不要假设项目页的面板、服务是同一版;页面只读本工坊的应用数据(`ctx.app.data` 已固定在本工坊,没有 `write`)。路由只写 `/w/:workshop/x/<页面>`,不写 `aliases`、`opens`。
11
12
  - **不放凭据**:接口身份由 Band 代理注入,插件代码和仓库里都不出现 token、连接串。
@@ -32,4 +32,4 @@ bed.dispose();
32
32
 
33
33
  `band publish <工坊仓库目录> --url <Band 服务地址> --workshop <id>` 先校验并要求工作区干净,用作者的 git 凭据推送远端同名分支(须与工坊发布分支一致),再用 `BAND_TOKEN` 的 Bearer 身份只调一次 POST releases,不调用工坊 GET。`--workshop` 必填,id 从工坊页地址 `/w/<id>` 获取。可 `--no-push` 跳过推送。不要将 token 写进工坊仓库或命令文本;真实服务发布依赖平台 token 功能,缺少鉴权时继续用页面。构建命令与带依赖预设在生产隔离端口未装配前仍关闭。
34
34
 
35
- `band preview [分支] --workshop <id> [--project <项目 id>]`:把已 push 的分支建成预览快照(只读工坊仓库、不发新版本),带 `--project` 时打印 `?preview=` 的项目链接,只有工坊管理员能打开;token 要 `workshops:preview` scope。预览页的写入会落到真实项目。
35
+ `band preview [分支] --workshop <id> [--project <项目 id>]`:把已 push 的分支建成预览快照(只读工坊仓库、不发新版本),带 `--project` 时打印 `?preview=` 的项目链接,只有工坊管理员能打开;token 要 `workshops:preview` scope。预览页的写入会落到打开的那个项目(试用项目就落在试用项目里)。
@@ -6,7 +6,7 @@
6
6
  "keywords": ["示例"],
7
7
  "type": "module",
8
8
  "peerDependencies": {
9
- "@kanyun-ai-infra/band-plugin-sdk": "^1.0.0",
9
+ "@kanyun-ai-infra/band-plugin-sdk": "^2.0.0",
10
10
  "@kanyun-ai-infra/band-project": "*"
11
11
  }
12
12
  }
@@ -210,7 +210,7 @@ input.field[type="number"] { font-variant-numeric: tabular-nums; }
210
210
  /* 输入框下面一行:提示、出错、计数。计数靠右,超了写 .over(DESIGN.md「控件」) */
211
211
  .field-note { display: flex; align-items: center; gap: 6px; margin: 0; min-height: 16px; font-size: var(--fs-badge); color: var(--muted); }
212
212
  .field-note.err { color: var(--bad); }
213
- .field-count { font-family: var(--mono); }
213
+ .field-count { font-family: var(--mono); white-space: nowrap; }
214
214
  .field-note > .field-count { margin-left: auto; }
215
215
  .field-count.over { color: var(--bad); }
216
216
 
package/dev-host/app.tsx CHANGED
@@ -34,6 +34,8 @@ import "./host.css";
34
34
  import * as dev from "virtual:band-dev";
35
35
  import { useEffect, useRef, useState } from "react";
36
36
  import { createRoot } from "react-dom/client";
37
+ import { devManagers } from "../src/dev-managers.ts";
38
+ import { inspectorOpenByDefault } from "../src/inspector-default.ts";
37
39
  import { DEV_HOST_PLUGIN } from "../src/inspector-plugins.ts";
38
40
  import { loadPlugins } from "../src/load-plugins.ts";
39
41
  import { Inspector } from "./Inspector.tsx";
@@ -117,11 +119,14 @@ async function boot() {
117
119
  }
118
120
  : base;
119
121
  const fixture = withStageDefs(withArtifacts(dev.fixture));
120
- const transport = createFixtureTransport(fixture, {
121
- actor: { kind: "human", id: member.id },
122
- defaultAgent: dev.agent,
123
- resources: dev.resources,
124
- });
122
+ const transport = createFixtureTransport(
123
+ { ...fixture, managers: devManagers(roleParam, dev.roles, member.id) },
124
+ {
125
+ actor: { kind: "human", id: member.id },
126
+ defaultAgent: dev.agent,
127
+ resources: dev.resources,
128
+ },
129
+ );
125
130
 
126
131
  // 插件入口并行导入;一个失败只让它进「没加载的插件」
127
132
  const official: LoadedPlugin[] = [];
@@ -312,6 +317,10 @@ function focusOf(s: Selection | null): string | undefined {
312
317
  }
313
318
 
314
319
  function App() {
320
+ // 夹具栏占 300px:视口不到 1600 默认收起,免得挤坏项目页右栏;收起时仍挂着,事件与诊断照常记
321
+ const [inspectorOpen, setInspectorOpen] = useState(() =>
322
+ inspectorOpenByDefault(window.innerWidth),
323
+ );
315
324
  return (
316
325
  <div className="dev-page">
317
326
  <header className="dev-bar">
@@ -341,16 +350,27 @@ function App() {
341
350
  ) : (
342
351
  <span className="chip plain">{member.displayName}</span>
343
352
  )}
353
+ <button
354
+ type="button"
355
+ className="btn"
356
+ aria-expanded={inspectorOpen}
357
+ aria-controls="dev-inspector-slot"
358
+ onClick={() => setInspectorOpen((v) => !v)}
359
+ >
360
+ 夹具
361
+ </button>
344
362
  </header>
345
363
  <div className="dev-body">
346
364
  <ProjectPage />
347
- <Inspector
348
- ctx={hostCtx}
349
- view={view}
350
- transport={transport}
351
- problems={problems}
352
- stageViews={stageViews}
353
- />
365
+ <div id="dev-inspector-slot" className="dev-inspector-slot" hidden={!inspectorOpen}>
366
+ <Inspector
367
+ ctx={hostCtx}
368
+ view={view}
369
+ transport={transport}
370
+ problems={problems}
371
+ stageViews={stageViews}
372
+ />
373
+ </div>
354
374
  </div>
355
375
  </div>
356
376
  );
package/dev-host/host.css CHANGED
@@ -63,6 +63,13 @@ body {
63
63
  .dev-project > .band-react-surface {
64
64
  display: contents;
65
65
  }
66
+ /* 夹具栏的槽:展开时不占自己的盒子(让 aside 直接当 .dev-body 的子项),收起时整块不显示 */
67
+ .dev-inspector-slot {
68
+ display: contents;
69
+ }
70
+ .dev-inspector-slot[hidden] {
71
+ display: none;
72
+ }
66
73
  /* 锁定插件替身只标位置 */
67
74
  .dev-inspector {
68
75
  width: 300px;
package/dist/bin.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-VTAJX7NN.js";
4
+ } from "./chunk-FGPWXAOA.js";
5
5
  import "./chunk-CL3FV65M.js";
6
- import "./chunk-JWZU3NOD.js";
7
- import "./chunk-TQHHHXXU.js";
6
+ import "./chunk-XPLYTHNX.js";
7
+ import "./chunk-LGYGWMSY.js";
8
8
 
9
9
  // src/bin.ts
10
10
  process.exitCode = await main(process.argv.slice(2));
@@ -1,5 +1,5 @@
1
1
  export { SHARED_MODULES } from '@kanyun-ai-infra/band-plugin-sdk';
2
- export { W as WORKSHOP_FORBIDDEN_IMPORTS, c as checkPlugin, a as checkPluginSources } from './workshop-repo-Uq6blxyt.js';
2
+ export { W as WORKSHOP_FORBIDDEN_IMPORTS, c as checkPlugin, a as checkPluginSources } from './workshop-repo-DqoVdcGu.js';
3
3
  import '@kanyun-ai-infra/band-contracts';
4
4
  import 'zod';
5
5
 
@@ -2,7 +2,7 @@ import {
2
2
  WORKSHOP_FORBIDDEN_IMPORTS,
3
3
  checkPlugin,
4
4
  checkPluginSources
5
- } from "./chunk-TQHHHXXU.js";
5
+ } from "./chunk-LGYGWMSY.js";
6
6
 
7
7
  // src/build-plugin.ts
8
8
  import { mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "fs";
@@ -10,7 +10,7 @@ import {
10
10
  officialProfilePath,
11
11
  resolvePluginRepo,
12
12
  workshopNameOf
13
- } from "./chunk-JWZU3NOD.js";
13
+ } from "./chunk-XPLYTHNX.js";
14
14
  import {
15
15
  IMPLICIT_STAGE,
16
16
  SELF_CONTAINED_EXTENSIONS,
@@ -29,7 +29,7 @@ import {
29
29
  rolePermissions,
30
30
  selfContainedProblems,
31
31
  workshopFileReader
32
- } from "./chunk-TQHHHXXU.js";
32
+ } from "./chunk-LGYGWMSY.js";
33
33
 
34
34
  // src/index.ts
35
35
  import { execFileSync } from "child_process";
@@ -310,6 +310,8 @@ function newPlugin(root, name, opts) {
310
310
  description: title,
311
311
  type: "module",
312
312
  peerDependencies: {
313
+ react: "^19.0.0",
314
+ "react-dom": "^19.0.0",
313
315
  "@kanyun-ai-infra/band-plugin-sdk": `^${BAND_PROTOCOL_VERSION}`,
314
316
  [PROJECT]: "*"
315
317
  }
@@ -432,6 +434,8 @@ ${t.manifest}`,
432
434
  // 不带 --passWithNoTests:收不到测试要红,不吞成绿(band#456)
433
435
  scripts: { check: "tsc -p tsconfig.json", test: "vitest run" },
434
436
  peerDependencies: {
437
+ react: "^19.0.0",
438
+ "react-dom": "^19.0.0",
435
439
  "@kanyun-ai-infra/band-plugin-sdk": "workspace:*",
436
440
  [PROJECT]: "workspace:*"
437
441
  },
@@ -642,7 +646,7 @@ import { parse } from "yaml";
642
646
  // package.json
643
647
  var package_default = {
644
648
  name: "@kanyun-ai-infra/band-cli",
645
- version: "0.1.1",
649
+ version: "0.2.1",
646
650
  description: "band \u547D\u4EE4\u884C\uFF1A\u65B0\u5EFA\u3001\u672C\u5730\u8C03\u8BD5\u3001\u6821\u9A8C\u4E0E\u53D1\u5E03 Band \u5DE5\u574A\u548C\u63D2\u4EF6",
647
651
  license: "UNLICENSED",
648
652
  type: "module",
@@ -657,7 +661,8 @@ var package_default = {
657
661
  },
658
662
  "./build": {
659
663
  types: "./dist/build-plugin.d.ts",
660
- import: "./dist/build-plugin.js"
664
+ import: "./dist/build-plugin.js",
665
+ default: "./dist/build-plugin.js"
661
666
  },
662
667
  "./catalog": {
663
668
  types: "./dist/plugin-entry.d.ts",
@@ -692,8 +697,8 @@ var package_default = {
692
697
  "@kanyun-ai-infra/band-plugin-react": "workspace:^",
693
698
  "@kanyun-ai-infra/band-plugin-sdk": "workspace:^",
694
699
  "es-module-lexer": "^2.3.2",
695
- react: "^18.3.1",
696
- "react-dom": "^18.3.1",
700
+ react: "^19.3.1",
701
+ "react-dom": "^19.3.1",
697
702
  semver: "^7.8.5",
698
703
  vite: "^6.0.7",
699
704
  yaml: "^2.6.1",
@@ -705,8 +710,8 @@ var package_default = {
705
710
  "@kanyun-ai-infra/band-tokens": "workspace:*",
706
711
  "@kanyun-ai-infra/band-workshop": "workspace:*",
707
712
  "@types/node": "^22.10.0",
708
- "@types/react": "^18.3.12",
709
- "@types/react-dom": "^18.3.1",
713
+ "@types/react": "^19.3.0",
714
+ "@types/react-dom": "^19.3.0",
710
715
  tsup: "^8.4.0",
711
716
  typescript: "5.9.3",
712
717
  vitest: "^4.0.17"
@@ -737,11 +742,13 @@ function newPluginRepo(parentDir, packageName, opts) {
737
742
  const title = opts.title ?? name;
738
743
  const dir = join2(resolve2(parentDir), name);
739
744
  if (existsSync2(dir)) throw new NewPluginError(`${dir} \u5DF2\u7ECF\u5B58\u5728`);
745
+ const react = opts.react === true;
746
+ const entryFile = react ? "src/index.tsx" : "src/index.ts";
740
747
  const rendered = renderPluginTemplate(opts.template, {
741
748
  title,
742
749
  ...opts.stage ? { stage: opts.stage } : {},
743
750
  id: name,
744
- entry: "./src/index.ts"
751
+ entry: `./${entryFile}`
745
752
  });
746
753
  const workshop = fixtureWorkshop(packageName, opts.template, name, opts.stage);
747
754
  try {
@@ -752,14 +759,16 @@ function newPluginRepo(parentDir, packageName, opts) {
752
759
  );
753
760
  }
754
761
  const files = {
755
- "package.json": `${JSON.stringify(packageJson(packageName, title), null, 2)}
762
+ "package.json": `${JSON.stringify(packageJson(packageName, title, react), null, 2)}
763
+ `,
764
+ "tsconfig.json": `${JSON.stringify(tsconfig(react), null, 2)}
756
765
  `,
757
766
  "plugin.yaml": rendered.manifest,
758
- "src/index.ts": rendered.code,
767
+ [entryFile]: react ? reactSource(opts.template, title, opts.stage, name) : rendered.code,
759
768
  "dev/workshop.yaml": workshop,
760
769
  "dev/fixture.ts": fixtureSource(opts.template, opts.stage),
761
770
  ".gitlab-ci.yml": CI(packageName),
762
- "README.md": readme(packageName, title, opts.template, name, parsed.scope),
771
+ "README.md": readme(packageName, title, opts.template, name, parsed.scope, react),
763
772
  ".gitignore": "node_modules/\ndist/\n"
764
773
  };
765
774
  for (const [f, body] of Object.entries(files)) {
@@ -773,7 +782,8 @@ function newPluginRepo(parentDir, packageName, opts) {
773
782
  hints: [
774
783
  `cd ${dir} && npm install\uFF1A\u88C5\u4E0A band \u547D\u4EE4\u884C\u4E0E\u63D2\u4EF6 SDK\uFF08devDependencies\uFF09`,
775
784
  "npx band dev .\uFF1A\u7528 dev/ \u5939\u5177\u5DE5\u574A\u8D77\u9875\u9762\uFF0C\u672C\u4ED3\u5E93\u7684\u63D2\u4EF6\u81EA\u52A8\u88C5\u4E0A",
776
- "npx band check .\uFF1A\u6821\u9A8C\u63D2\u4EF6\u4E0E\u5939\u5177\u5DE5\u574A\u7684\u88C5\u914D",
785
+ "npx band check .\uFF1A\u6821\u9A8C\u63D2\u4EF6\u4E0E\u5939\u5177\u5DE5\u574A\u7684\u88C5\u914D\uFF08\u4E0D\u67E5\u7C7B\u578B\uFF09",
786
+ "npm run typecheck\uFF1A\u8DD1 tsc --noEmit \u67E5\u7C7B\u578B\uFF08band check \u4E0D\u67E5\uFF09",
777
787
  placementHint(opts.template, packageName, name, opts.stage),
778
788
  "\u53D1\u5E03\u8FD8\u6CA1\u63A5\u4E0A\uFF08\u63D2\u4EF6\u7531 Band \u6253\u5305\u5206\u53D1\uFF0C\u4E0D\u7ECF npm \u53D1\u5305\uFF09\uFF1A\u73B0\u5728 CI \u6A21\u677F\u53EA\u8DD1 band check"
779
789
  ]
@@ -786,7 +796,7 @@ function placementHint(template, packageName, name, stage) {
786
796
  return `\u9636\u6BB5 ${String(stage)} \u7684\u754C\u9762\u4F1A\u51FA\u73B0\u5728\u5F15\u7528\u5B83\u7684\u5DE5\u574A\u7684\u9636\u6BB5\u8BE6\u60C5\u91CC`;
787
797
  }
788
798
  var PROJECT2 = "@kanyun-ai-infra/band-project";
789
- function packageJson(packageName, title) {
799
+ function packageJson(packageName, title, react) {
790
800
  return {
791
801
  name: packageName,
792
802
  version: "0.1.0",
@@ -794,18 +804,46 @@ function packageJson(packageName, title) {
794
804
  license: "UNLICENSED",
795
805
  type: "module",
796
806
  files: ["src", "plugin.yaml", "README.md"],
797
- scripts: { dev: "band dev .", check: "band check ." },
807
+ scripts: { dev: "band dev .", check: "band check .", typecheck: "tsc --noEmit" },
798
808
  peerDependencies: {
809
+ react: "^19.0.0",
810
+ "react-dom": "^19.0.0",
799
811
  "@kanyun-ai-infra/band-plugin-sdk": `^${BAND_PROTOCOL_VERSION2}`,
800
812
  [PROJECT2]: "*"
801
813
  },
802
814
  peerDependenciesMeta: { [PROJECT2]: { optional: true } },
803
815
  devDependencies: {
804
816
  "@kanyun-ai-infra/band-cli": `^${CLI_VERSION}`,
805
- "@kanyun-ai-infra/band-plugin-sdk": `^${BAND_PROTOCOL_VERSION2}`
817
+ "@kanyun-ai-infra/band-plugin-sdk": `^${BAND_PROTOCOL_VERSION2}`,
818
+ typescript: "^5.9.3",
819
+ // 用 React 写才要:宿主与 band dev 提供运行时的 React,这些只给类型检查与编辑器提示
820
+ ...react ? {
821
+ "@kanyun-ai-infra/band-plugin-react": `^${PLUGIN_REACT_RANGE}`,
822
+ "@types/react": "^19.0.0",
823
+ "@types/react-dom": "^19.0.0",
824
+ react: "^19.0.0",
825
+ "react-dom": "^19.0.0"
826
+ } : {}
806
827
  }
807
828
  };
808
829
  }
830
+ var PLUGIN_REACT_RANGE = "0.2.1";
831
+ function tsconfig(react) {
832
+ return {
833
+ compilerOptions: {
834
+ target: "ES2022",
835
+ module: "ESNext",
836
+ moduleResolution: "bundler",
837
+ lib: ["ES2023", "DOM", "DOM.Iterable"],
838
+ strict: true,
839
+ noUncheckedIndexedAccess: true,
840
+ skipLibCheck: true,
841
+ noEmit: true,
842
+ ...react ? { jsx: "react-jsx" } : {}
843
+ },
844
+ include: ["src", "dev"]
845
+ };
846
+ }
809
847
  function fixtureWorkshop(packageName, template, name, stage) {
810
848
  const head = `# \u72EC\u7ACB\u63D2\u4EF6 ${packageName} \u7684\u672C\u5730\u5939\u5177\u5DE5\u574A\uFF1Aband dev \u8D77\u9879\u76EE\u9875\u3001band check \u67E5\u88C5\u914D\u7528\uFF0C\u4E0D\u53D1\u5E03\u3001\u4E0D\u8FDB\u4EFB\u4F55\u771F\u5B9E\u5DE5\u574A\u3002
811
849
  # \u672C\u4ED3\u5E93\u7684\u63D2\u4EF6\u7531\u547D\u4EE4\u76F4\u63A5\u88C5\u4E0A\uFF0C\u4E0D\u7528\u5199\u8FDB views.plugins\u3002
@@ -849,6 +887,85 @@ views:
849
887
  `;
850
888
  }
851
889
  var q2 = (s) => JSON.stringify(s);
890
+ function reactSource(template, title, stage, id) {
891
+ const head = (what) => `/**
892
+ * ${what.replace(/\*\//g, "* /").replace(/[\r\n]+/g, " ")}
893
+ * \u53EA\u7528\u516C\u5F00 ctx\uFF1B\u672C\u5730 \`band dev\` \u8FB9\u5199\u8FB9\u770B\uFF0C\`npm run typecheck\` \u67E5\u7C7B\u578B\uFF0C\u63D0\u4EA4\u524D \`band check\`\u3002
894
+ */
895
+ `;
896
+ const imports = `import { reactMount, useCtxData } from "@kanyun-ai-infra/band-plugin-react";
897
+ import { type ProjectCtx, definePlugin } from "@kanyun-ai-infra/band-plugin-sdk";
898
+ import { useState } from "react";
899
+ `;
900
+ if (template === "panel")
901
+ return `${head(`${title}\uFF1A\u4E00\u4E2A\u9762\u677F\u3002\u663E\u793A\u5F53\u524D\u7248\u672C\u7684\u6587\u4EF6\u6570\u3002`)}${imports.replace('import { useState } from "react";\n', "")}
902
+ function Panel({ ctx }: { ctx: ProjectCtx }) {
903
+ const { data, error } = useCtxData(ctx, async () => ctx.version.current(), [], "version.*");
904
+ if (error) return <p>{error}</p>;
905
+ if (data === undefined) return <p>\u8BFB\u53D6\u4E2D\u2026</p>;
906
+ return <p>{data ? \`\u7248\u672C \${data.id}\uFF1A\${data.entries.length} \u4E2A\u6587\u4EF6\` : "\uFF08\u8FD8\u6CA1\u6709\u7248\u672C\uFF09"}</p>;
907
+ }
908
+
909
+ export default definePlugin({
910
+ surfaces: {
911
+ main: reactMount((ctx: ProjectCtx) => <Panel ctx={ctx} />),
912
+ },
913
+ });
914
+ `;
915
+ if (template === "viewer")
916
+ return `${head(`${title}\uFF1A\u4E00\u4E2A\u67E5\u770B\u5668\u3002\u5217\u51FA\u5F53\u524D\u7248\u672C\u7684\u6587\u4EF6\uFF0C\u70B9\u4E00\u4E2A\u770B\u5185\u5BB9\u3002`)}${imports}
917
+ function Viewer({ ctx }: { ctx: ProjectCtx }) {
918
+ const { data: version, error } = useCtxData(ctx, async () => ctx.version.current(), [], "version.*");
919
+ const [body, setBody] = useState("");
920
+ if (error) return <p>{error}</p>;
921
+ return (
922
+ <>
923
+ <ul>
924
+ {(version?.entries ?? []).map((e) => (
925
+ <li key={e.path}>
926
+ <button
927
+ type="button"
928
+ onClick={async () => setBody(new TextDecoder().decode(await ctx.version.readFile(e.path)))}
929
+ >
930
+ {e.path}
931
+ </button>
932
+ </li>
933
+ ))}
934
+ </ul>
935
+ <pre>{body}</pre>
936
+ </>
937
+ );
938
+ }
939
+
940
+ export default definePlugin({
941
+ surfaces: {
942
+ ${JSON.stringify(id)}: reactMount((ctx: ProjectCtx) => <Viewer ctx={ctx} />),
943
+ },
944
+ });
945
+ `;
946
+ const st = JSON.stringify(stage ?? "");
947
+ return `${head(`${title}\uFF1A\u9636\u6BB5 ${stage ?? ""} \u7684\u754C\u9762\u3002\u663E\u793A\u9636\u6BB5\u72B6\u6001\uFF0C\u53EF\u4EE5\u542F\u52A8\u3002`)}${imports.replace('import { useState } from "react";\n', "")}
948
+ const STAGE = ${st};
949
+
950
+ function StageView({ ctx }: { ctx: ProjectCtx }) {
951
+ const { data, error } = useCtxData(ctx, () => ctx.stages.get(STAGE), [], "stage.*");
952
+ return (
953
+ <>
954
+ <p>{error ?? (data ? \`\${data.stage}\uFF1A\${data.status}\` : "\u8BFB\u53D6\u4E2D\u2026")}</p>
955
+ <button type="button" onClick={() => void ctx.stages.start(STAGE)}>
956
+ \u542F\u52A8
957
+ </button>
958
+ </>
959
+ );
960
+ }
961
+
962
+ export default definePlugin({
963
+ surfaces: {
964
+ main: reactMount((ctx: ProjectCtx) => <StageView ctx={ctx} />),
965
+ },
966
+ });
967
+ `;
968
+ }
852
969
  function fixtureSource(template, stage) {
853
970
  const stages = template === "stage-view" ? ` stages: [{ stage: ${q2(stage ?? "")}, status: "ready" }],
854
971
  ` : "";
@@ -909,7 +1026,8 @@ band-check:
909
1026
  - npx band check .
910
1027
  `;
911
1028
  }
912
- function readme(packageName, title, template, name, scope) {
1029
+ function readme(packageName, title, template, name, scope, react) {
1030
+ const entry = react ? "src/index.tsx" : "src/index.ts";
913
1031
  const place = template === "panel" ? `\`views.panels\`\uFF08\u672C\u4ED3\u5E93\u7684\u5939\u5177\u653E\u5728\u53F3\u680F\uFF1A\`${packageName}/main\`\uFF09` : template === "viewer" ? `\`views.artifactTypes.<\u4EA7\u7269\u7C7B\u578B>.viewer\`\uFF08\u672C\u4ED3\u5E93\u7684\u5939\u5177\u628A \`demo\` \u7ED1\u5230 \`${packageName}/${name}\`\uFF09` : "\u5F15\u7528\u5B83\u7684\u5DE5\u574A\u7684\u6D41\u7A0B\u9636\u6BB5\u8BE6\u60C5\u91CC";
914
1032
  return `# ${packageName}
915
1033
 
@@ -921,7 +1039,8 @@ ${title}\uFF1A\u4E00\u4E2A\u72EC\u7ACB\u7684 Band \u63D2\u4EF6\uFF08\u4E0D\u5C5E
921
1039
  |---|---|
922
1040
  | \`package.json\` | \u8EAB\u4EFD\u4E0E\u7248\u672C\uFF1A\u5305\u540D\u3001\u534F\u8BAE\u8303\u56F4\uFF1BdevDependencies \u5E26 band \u547D\u4EE4\u884C\u4E0E\u63D2\u4EF6 SDK |
923
1041
  | \`plugin.yaml\` | \u89C6\u56FE\u9762\u6E05\u5355\uFF1A\u5F80\u54EA\u4E9B\u63D2\u69FD\u8D21\u732E |
924
- | \`src/index.ts\` | \u5165\u53E3\uFF0C\u9ED8\u8BA4\u5BFC\u51FA \`definePlugin({ surfaces })\` |
1042
+ | \`${entry}\` | \u5165\u53E3\uFF0C\u9ED8\u8BA4\u5BFC\u51FA \`definePlugin({ surfaces })\`${react ? "\uFF0C\u7528 `reactMount` \u6302 React \u7EC4\u4EF6" : ""} |
1043
+ | \`tsconfig.json\` | \`npm run typecheck\`\uFF08\`tsc --noEmit\`\uFF09\u7528\uFF1B\`band check\` \u4E0D\u67E5\u7C7B\u578B |
925
1044
  | \`dev/workshop.yaml\` | \u672C\u5730\u5939\u5177\u5DE5\u574A\uFF1A\u6700\u5C0F\u5B9A\u4E49\uFF0C\u53EA\u7ED9 \`band dev\` / \`band check\` \u7528\uFF0C\u4E0D\u53D1\u5E03 |
926
1045
  | \`dev/fixture.ts\` | \u5939\u5177\uFF1A\u793A\u4F8B\u4EA7\u7269\u3001\u7248\u672C\u4E0E\u6587\u4EF6 |
927
1046
  | \`.gitlab-ci.yml\` | CI \u6A21\u677F\uFF1A\u73B0\u5728\u8DD1 \`band check\`\uFF1B\u5355\u6D4B\u3001\u9632\u6CC4\u9732\u626B\u63CF\u4E0E\u53D1\u5E03\u8FDB\u884C\u4E2D |
@@ -933,7 +1052,8 @@ ${title}\uFF1A\u4E00\u4E2A\u72EC\u7ACB\u7684 Band \u63D2\u4EF6\uFF08\u4E0D\u5C5E
933
1052
  \`\`\`bash
934
1053
  npm install # \u88C5\u4E0A devDependencies \u91CC\u7684 band \u547D\u4EE4\u884C\u4E0E\u63D2\u4EF6 SDK
935
1054
  npx band dev . # \u7528 dev/ \u5939\u5177\u5DE5\u574A\u8D77\u9879\u76EE\u9875\uFF0C\u672C\u4ED3\u5E93\u7684\u63D2\u4EF6\u81EA\u52A8\u88C5\u4E0A
936
- npx band check . # \u6821\u9A8C package.json\u3001plugin.yaml \u4E0E\u5939\u5177\u5DE5\u574A\u7684\u88C5\u914D
1055
+ npx band check . # \u6821\u9A8C package.json\u3001plugin.yaml \u4E0E\u5939\u5177\u5DE5\u574A\u7684\u88C5\u914D\uFF08\u4E0D\u67E5\u4EE3\u7801\u548C\u7C7B\u578B\uFF09
1056
+ npm run typecheck # tsc --noEmit \u67E5\u7C7B\u578B
937
1057
  \`\`\`
938
1058
 
939
1059
  ## \u53D1\u5E03\uFF08\u8FDB\u884C\u4E2D\uFF09
@@ -1063,9 +1183,19 @@ var PUBLISH_LABELS = {
1063
1183
  404: "\u5DE5\u574A\u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5 --workshop id",
1064
1184
  409: "\u53D1\u5E03\u51B2\u7A81\uFF0C\u8BF7\u786E\u8BA4\u5DE5\u574A\u53D1\u5E03\u5206\u652F\u7684\u63D0\u4EA4\u4E0E\u672C\u5730 HEAD \u4E00\u81F4"
1065
1185
  };
1186
+ async function hasCredentialsFile() {
1187
+ try {
1188
+ await readFile(join5(homedir(), ".config", "band", "credentials.json"), "utf8");
1189
+ return true;
1190
+ } catch {
1191
+ return false;
1192
+ }
1193
+ }
1066
1194
  async function connectBand(urlOption, failureLabels = PUBLISH_LABELS, needScope = "workshops:publish") {
1067
1195
  let url = urlOption ?? process.env.BAND_URL;
1068
1196
  let token = process.env.BAND_TOKEN;
1197
+ if (!url && !token && !await hasCredentialsFile())
1198
+ throw new PublishError("\u7F3A\u5C11\u670D\u52A1\u5730\u5740\uFF1A\u7528 --url <\u5730\u5740>\uFF08\u6216\u8BBE BAND_URL\uFF09\uFF0C\u5E76\u914D\u7F6E BAND_TOKEN");
1069
1199
  if (!token) {
1070
1200
  let saved;
1071
1201
  try {
@@ -1087,11 +1217,11 @@ async function connectBand(urlOption, failureLabels = PUBLISH_LABELS, needScope
1087
1217
  }
1088
1218
  if (requestedOrigin && requestedOrigin !== savedOrigin)
1089
1219
  throw new PublishError("\u76EE\u6807\u670D\u52A1\u4E0E\u7528\u6237\u51ED\u636E\u6587\u4EF6\u4E0D\u5339\u914D\uFF0C\u8BF7\u4E3A\u76EE\u6807\u670D\u52A1\u63D0\u4F9B BAND_TOKEN");
1090
- url ??= saved.url;
1220
+ if (!url) url = saved.url;
1091
1221
  token = saved.token;
1092
1222
  }
1093
- if (!url || !token || /\s/.test(token))
1094
- throw new PublishError("\u8BF7\u914D\u7F6E\u5408\u6CD5\u7684 BAND_URL \u4E0E BAND_TOKEN");
1223
+ if (!url) throw new PublishError("\u7F3A\u5C11\u670D\u52A1\u5730\u5740\uFF1A\u7528 --url <\u5730\u5740> \u6216\u8BBE BAND_URL");
1224
+ if (!token || /\s/.test(token)) throw new PublishError("\u8BF7\u914D\u7F6E\u5408\u6CD5\u7684 BAND_TOKEN");
1095
1225
  let base;
1096
1226
  try {
1097
1227
  base = new URL(url);
@@ -1813,7 +1943,7 @@ var USAGE_BASE = `\u7528\u6CD5\uFF1A
1813
1943
  band preview [\u5206\u652F\u6216\u63D0\u4EA4] [--url <Band \u670D\u52A1\u5730\u5740>] --workshop <id> [--project <\u9879\u76EE id>]
1814
1944
  band dev [\u5DE5\u574A\u4ED3\u5E93\u76EE\u5F55 | \u72EC\u7ACB\u63D2\u4EF6\u4ED3\u5E93\u76EE\u5F55] [--port 5310] [--host 127.0.0.1]
1815
1945
  band new plugin <\u540D> --template panel|viewer|stage-view [--stage <\u9636\u6BB5>] [--title <\u6807\u9898>] [--dir <\u5DE5\u574A\u4ED3\u5E93\u76EE\u5F55>]
1816
- band new plugin-repo @<\u56E2\u961F>/<\u540D> --template panel|viewer|stage-view [--stage <\u9636\u6BB5>] [--title <\u6807\u9898>] [--dir <\u7236\u76EE\u5F55>]
1946
+ band new plugin-repo @<\u56E2\u961F>/<\u540D> --template panel|viewer|stage-view [--react] [--stage <\u9636\u6BB5>] [--title <\u6807\u9898>] [--dir <\u7236\u76EE\u5F55>]
1817
1947
  band new workshop <\u76EE\u5F55> [--example video]
1818
1948
  band new skill [--dir <\u4ED3\u5E93\u76EE\u5F55>]
1819
1949
  band --version`;
@@ -1942,7 +2072,11 @@ async function main(argv) {
1942
2072
  return 0;
1943
2073
  }
1944
2074
  if (cmd === "new") {
1945
- const { args, flags } = parseArgs(rest, ["template", "stage", "title", "dir"], ["official"]);
2075
+ const { args, flags } = parseArgs(
2076
+ rest,
2077
+ ["template", "stage", "title", "dir"],
2078
+ ["official", "react"]
2079
+ );
1946
2080
  const [kind, name] = args;
1947
2081
  if (kind !== "plugin" && kind !== "plugin-repo" || !name) {
1948
2082
  console.error(usage());
@@ -1953,6 +2087,10 @@ async function main(argv) {
1953
2087
  console.error(`--template \u53EA\u80FD\u662F ${PLUGIN_TEMPLATES.join(" | ")}`);
1954
2088
  return 2;
1955
2089
  }
2090
+ if (kind === "plugin" && flags.react) {
2091
+ console.error("--react \u53EA\u7528\u4E8E band new plugin-repo\uFF08\u5DE5\u574A\u4ED3\u5E93\u91CC\u7684\u63D2\u4EF6\u81EA\u5DF1\u5199 .tsx \u5165\u53E3\uFF09");
2092
+ return 2;
2093
+ }
1956
2094
  if (kind === "plugin-repo") {
1957
2095
  if (flags.official) {
1958
2096
  console.error("--official \u53EA\u7528\u4E8E band new plugin\uFF1A\u72EC\u7ACB\u63D2\u4EF6\u4ED3\u5E93\u4E0D\u751F\u6210\u5B98\u65B9\u63D2\u4EF6");
@@ -1961,7 +2099,8 @@ async function main(argv) {
1961
2099
  const r2 = newPluginRepo(flags.dir ?? ".", name, {
1962
2100
  template,
1963
2101
  ...flags.stage ? { stage: flags.stage } : {},
1964
- ...flags.title ? { title: flags.title } : {}
2102
+ ...flags.title ? { title: flags.title } : {},
2103
+ ...flags.react ? { react: true } : {}
1965
2104
  });
1966
2105
  for (const f of r2.files) console.log(`\u2713 ${relative(flags.dir ?? ".", join7(r2.dir, f))}`);
1967
2106
  for (const h of r2.hints) console.log(`\u4E0B\u4E00\u6B65\uFF1A${h}`);
@@ -1980,7 +2119,7 @@ async function main(argv) {
1980
2119
  if (cmd === "dev") {
1981
2120
  const { args, flags } = parseArgs(rest, ["port", "host"]);
1982
2121
  const port = flags.port === void 0 ? void 0 : parsePort(flags.port);
1983
- const { startDevServer } = await import("./dev-server-SB5FMSVP.js");
2122
+ const { startDevServer } = await import("./dev-server-IBR3PKDE.js");
1984
2123
  const server = await startDevServer(args[0] ?? ".", {
1985
2124
  ...port !== void 0 ? { port } : {},
1986
2125
  ...flags.host ? { host: flags.host } : {}