@easytwin/devkit 0.1.1 → 0.1.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 +8 -4
- package/dist/bin.js +761 -153
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts +310 -21
- package/dist/index.js +1069 -130
- package/dist/index.js.map +1 -1
- package/dist/runtime-types/index.d.ts +6 -1
- package/package.json +1 -1
- package/skills/easytwin-bootstrap/SKILL.md +10 -5
- package/skills/easytwin-core/SKILL.md +2 -2
- package/skills/easytwin-core/references/engine.md +2 -2
- package/skills/easytwin-develop/SKILL.md +7 -6
- package/skills/easytwin-render/SKILL.md +56 -17
- package/skills/easytwin-render/references/intro.md +8 -4
- package/skills/easytwin-render/references/scene-and-assets.md +1 -1
- package/skills/easytwin-scene/SKILL.md +2 -2
- package/skills/easytwin-upload/SKILL.md +25 -12
|
@@ -15,17 +15,22 @@ description: 当用户要开始使用 EasyTwin DevKit、配置应用级凭证(Ap
|
|
|
15
15
|
"appSecret": "必填",
|
|
16
16
|
"env": "可选,prod=正式 / test=测试,缺省 prod",
|
|
17
17
|
"baseUrl": "可选,缺省按 env 选官方域名",
|
|
18
|
-
"ossUrl": "可选,缺省官方 OSS"
|
|
18
|
+
"ossUrl": "可选,缺省官方 OSS",
|
|
19
|
+
"opAccountId": "可选,过渡期网关头 op-account-id;env=test 缺省 25",
|
|
20
|
+
"opUserId": "可选,过渡期网关头 op-user-id;env=test 缺省 25",
|
|
21
|
+
"spaceId": "可选,过渡期网关头 space-id;env=test 缺省 54",
|
|
22
|
+
"scenes": "可选,由 easytwin scene list 写入的场景摘要,不含 JSON 本体"
|
|
19
23
|
}
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
- 环境变量 `EASYTWIN_APP_ID` / `EASYTWIN_APP_SECRET` / `EASYTWIN_BASE_URL` / `EASYTWIN_ENV` / `EASYTWIN_OSS_URL` 优先于文件(CI 与不落盘场景)。
|
|
23
|
-
- 官方 API:正式 `http://saas-twin.k8s.dtstack.cn/`、测试 `http://
|
|
26
|
+
- 环境变量 `EASYTWIN_APP_ID` / `EASYTWIN_APP_SECRET` / `EASYTWIN_BASE_URL` / `EASYTWIN_ENV` / `EASYTWIN_OSS_URL` 优先于文件(CI 与不落盘场景)。过渡期另有 `EASYTWIN_OP_ACCOUNT_ID` / `EASYTWIN_OP_USER_ID` / `EASYTWIN_SPACE_ID`(当前测试后端走 OP 网关,免网关接口到位后删除)。
|
|
27
|
+
- 官方 API:正式 `http://saas-twin.k8s.dtstack.cn/`、测试 `http://172.16.125.3:10100/`;缺省按 env 选择,`EASYTWIN_BASE_URL` 始终优先。
|
|
24
28
|
- 官方 OSS:`https://dt-easyv-test.oss-cn-hangzhou.aliyuncs.com/`,供 twin runtime 加载 webp wasm / draco / 组件脚本;`EASYTWIN_OSS_URL` 始终优先。
|
|
25
29
|
- 该文件含密钥,**永不入库**:`init` 已负责 gitignore,不要把它提交进版本库。
|
|
26
|
-
-
|
|
30
|
+
- `scenes` 由 `easytwin scene list`(或插件刷新场景树)写入,下次 list 会全量覆盖;`init` 重写配置时不会保留旧列表。
|
|
31
|
+
- **本地测试**:`appId` 与 `appSecret` 都填 `test` 时进入本地测试模式,scene/upload/pull 走本地 mock、不发网络请求(见 easytwin-scene / easytwin-upload)。仅限本地联调,严禁用假凭据碰真实服务端。
|
|
27
32
|
|
|
28
33
|
## 步骤
|
|
29
34
|
|
|
30
35
|
1. 若项目还没有 `easytwin.config.json`,运行 `easytwin init` 并按提示输入。
|
|
31
|
-
2. 校验:`easytwin scene list`
|
|
36
|
+
2. 校验:`easytwin scene list` 能列出场景即凭据有效,并会把场景 id/名称写入 `easytwin.config.json.scenes`;报错则检查 appId / appSecret 或环境变量覆盖。
|
|
@@ -5,7 +5,7 @@ description: 当用户要理解 EasyTwin 引擎内核(类层级、RuntimeEngine
|
|
|
5
5
|
|
|
6
6
|
# 引擎内核(easytwin-runtime core)
|
|
7
7
|
|
|
8
|
-
对应
|
|
8
|
+
对应 `@easytwin/runtime` 的 `src/core/` 目录:引擎本体、场景、组件基类与基础设施。第三方应用入口是 TwinApp 子类,主流程见 `easytwin-render`;本技能是引擎内部 API 参考。
|
|
9
9
|
|
|
10
10
|
## 核心关系速览
|
|
11
11
|
|
|
@@ -22,4 +22,4 @@ description: 当用户要理解 EasyTwin 引擎内核(类层级、RuntimeEngine
|
|
|
22
22
|
- 需要"相机体系(Camera/SceneCamera/CameraControls/focus)"时读 `references/camera.md`
|
|
23
23
|
- 需要"物理体系(PhysicsManager/PhysicsScene/物理开关)"时读 `references/physics.md`
|
|
24
24
|
|
|
25
|
-
组件生命周期钩子、状态/数据 API 与序列化结构分别在 `easytwin-render` 的 `references/lifecycle-events.md` 与 `references/scene-and-assets.md`,本技能不重复(虚拟子要素的序列化结构见本技能 `references/virtual-components.md`)。
|
|
25
|
+
组件生命周期钩子、状态/数据 API 与序列化结构分别在 `easytwin-render` 的 `references/lifecycle-events.md` 与 `references/scene-and-assets.md`,本技能不重复(虚拟子要素的序列化结构见本技能 `references/virtual-components.md`)。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 概览
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
TwinApp 从 `ctx.engine` 取用本对象。一个 `RuntimeEngine` 对应一个 DOM 容器(`engine.container`):
|
|
6
6
|
|
|
7
7
|
- 注册并初始化五个 manager:`ResourceManager` / `SceneManager` / `CustomComponentManager` / `EditorActionsManager` / `PhysicsManager`;
|
|
8
8
|
- 启动 `requestAnimationFrame` 渲染循环,每帧 `Time.update()` → `SceneManager.updateScene(deltaTime)`;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## create 与 EngineConfiguration
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
宿主创建入口 `RuntimeEngine.create(config)`(静态、异步)。TwinApp 用 `ctx.engine`,不必再调:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
const engine = await RuntimeEngine.create({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: easytwin-develop
|
|
3
|
-
description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体开发工作流(
|
|
3
|
+
description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体开发工作流(配置凭证→拉工作区代码→拉场景→写 TwinApp 子类→上传)、或询问"接下来该做什么/从哪开始"时使用。其余 EasyTwin 技能的总纲。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# EasyTwin 开发工作流
|
|
@@ -8,9 +8,10 @@ description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体
|
|
|
8
8
|
EasyTwin DevKit 是 EasyTwin 第三方应用开发工具集。典型工作流:
|
|
9
9
|
|
|
10
10
|
1. **配置凭证**:运行 `easytwin init` 生成项目级 `easytwin.config.json`(App ID / App Secret)。详见 `easytwin-bootstrap`。
|
|
11
|
-
2.
|
|
12
|
-
3.
|
|
13
|
-
4.
|
|
11
|
+
2. **拉取工作区代码**:`easytwin pull` 从服务端下载代码;远端为空则写入默认 TwinApp `src/main.ts`;本地已有文件时先 diff,默认只补缺失。详见 `easytwin-upload`。
|
|
12
|
+
3. **拉取场景**:`easytwin scene list` 列出场景,`easytwin scene pull <id>` 拉取场景 JSON 到本地,作为开发参考与预览输入。详见 `easytwin-scene`。
|
|
13
|
+
4. **编写渲染功能**:在工作区 `src/main.ts` 写 TwinApp 子类(`import { TwinApp } from "@easytwin/apps"`,`export default class App extends TwinApp { init; onSceneLoaded; onUpdate; ... }`)。类型由 `easytwin skills sync` 分发。编译用 `easytwin bundle`,运行用插件预览页底部 Run。可上传子集只用 runtime 五件套导出;整包 API 仅本地预览。引擎内核见 `easytwin-core`。详见 `easytwin-render`(主力技能)。
|
|
14
|
+
5. **上传产物**:`easytwin upload <dir>` 全量覆盖上传到服务端,不可逆。详见 `easytwin-upload`。
|
|
14
15
|
|
|
15
16
|
## 何时读哪个技能
|
|
16
17
|
|
|
@@ -20,10 +21,10 @@ EasyTwin DevKit 是 EasyTwin 第三方应用开发工具集。典型工作流:
|
|
|
20
21
|
| 列场景、拉场景 JSON | easytwin-scene |
|
|
21
22
|
| 用 twin runtime 写渲染 | easytwin-render |
|
|
22
23
|
| 理解引擎内核 / 基类 / 相机 / 物理 | easytwin-core |
|
|
23
|
-
|
|
|
24
|
+
| 上传 / 拉取工作区代码 | easytwin-upload |
|
|
24
25
|
|
|
25
26
|
> 场景 JSON 格式以 easytwin-runtime 的 `SceneJson` 为准,详见 easytwin-scene。
|
|
26
27
|
|
|
27
28
|
## 本地测试
|
|
28
29
|
|
|
29
|
-
没有凭据或不想动服务端时,把 `appId` / `appSecret` 都设为 `test` 即进入本地测试模式:`scene list` / `scene pull` 读 devkit 包内的 `scene.example.json`,`upload`
|
|
30
|
+
没有凭据或不想动服务端时,把 `appId` / `appSecret` 都设为 `test` 即进入本地测试模式:`scene list` / `scene pull` 读 devkit 包内的 `scene.example.json`,`upload` 只做本地空跑,`pull` 按远端为空写入默认 `src/main.ts`(已有则不覆盖),这三条不发服务端请求。插件里的场景预览仍是三维场景页(打包的 twin runtime + 本地示例 JSON),系统库(draco/basis/webp)与组件脚本按官方 OSS(=ossUrl)在线加载。预览页 Run 在 mock 下同样可用。
|
|
@@ -1,35 +1,74 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: easytwin-render
|
|
3
|
-
description: 当用户要用 EasyTwin twin runtime 编写渲染功能(写 src/main.ts、预览页 Run、easytwin bundle、加载场景、开发自定义组件、调用渲染 API)时使用。这是 EasyTwin 渲染开发的唯一入口技能。
|
|
3
|
+
description: 当用户要用 EasyTwin twin runtime 编写渲染功能(写 src/main.ts TwinApp 子类、class extends TwinApp、预览页 Run、easytwin bundle、加载场景、开发自定义组件、调用渲染 API)时使用。这是 EasyTwin 渲染开发的唯一入口技能。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 用 twin runtime 开发渲染功能
|
|
7
7
|
|
|
8
|
-
`@easytwin/runtime` 是商业包,公网 npm
|
|
8
|
+
`@easytwin/runtime` 是商业包,公网 npm 不存在,类型由 `easytwin skills sync` 写入 `.easytwin/types/`。`TwinApp` 从 `@easytwin/apps` 引入(同样由 sync 分发)。运行走预览页底部 **Run**,或 `easytwin bundle` 做编译校验。
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 编写 TwinApp 子类(可上传子集)
|
|
11
11
|
|
|
12
|
-
工作区固定入口 `src/main.ts
|
|
12
|
+
工作区固定入口 `src/main.ts`。依赖只允许 `@easytwin/runtime` 与 `@easytwin/apps`(相对路径本地 TS 可以)。`export default` 必须是 `TwinApp` 子类:
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
import { THREE } from "@easytwin/runtime";
|
|
16
|
+
import { TwinApp, type TwinAppContext } from "@easytwin/apps";
|
|
17
|
+
|
|
18
|
+
export default class App extends TwinApp {
|
|
19
|
+
async init(ctx: TwinAppContext) {
|
|
20
|
+
// engine / container 已有;scene / camera / runtimeScene 为 null
|
|
21
|
+
void ctx;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async onSceneLoaded(ctx: TwinAppContext) {
|
|
25
|
+
const mesh = new THREE.Mesh(
|
|
26
|
+
new THREE.BoxGeometry(1, 1, 1),
|
|
27
|
+
new THREE.MeshBasicMaterial({ color: 0x44aa88 }),
|
|
28
|
+
);
|
|
29
|
+
ctx.scene?.add(mesh);
|
|
30
|
+
ctx.sceneCleanup(() => {
|
|
31
|
+
ctx.scene?.remove(mesh);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onUpdate(ctx: TwinAppContext, delta: number, elapsed: number) {
|
|
36
|
+
void ctx;
|
|
37
|
+
void delta;
|
|
38
|
+
void elapsed;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onBeforeSceneUnload(ctx: TwinAppContext) {
|
|
42
|
+
void ctx;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onDispose(ctx: TwinAppContext) {
|
|
46
|
+
void ctx;
|
|
47
|
+
}
|
|
23
48
|
}
|
|
24
49
|
```
|
|
25
50
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
51
|
+
等价对象写法:`export default defineApp({ init, onSceneLoaded, onUpdate, ... })`。宿主只认这两种;函数导出(旧 `main`)会报错。
|
|
52
|
+
|
|
53
|
+
可上传到在线 TwinApp 的 runtime 导出名只有:`THREE`、`RuntimeEngine`、`SceneManager`、`LoadSceneMode`、`convertObjToComponentJson`。超出这些名字本地能编过并 warning,在线会失败。
|
|
54
|
+
|
|
55
|
+
生命周期由宿主驱动。引擎与场景已在预览页创建;`init` 里场景字段为 null,物体与事件写在 `onSceneLoaded`,用 `ctx.sceneCleanup` 对称拆除。
|
|
56
|
+
|
|
57
|
+
| 钩子 | 时机 |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `init` | 引擎 / 容器已有;场景字段为 null |
|
|
60
|
+
| `onSceneLoaded` | 宿主 `loadScene` 之后 |
|
|
61
|
+
| `onUpdate` | 引擎时钟每帧(加载中不调);仅此钩子 throw 走 `onError`(返回 `true` 继续) |
|
|
62
|
+
| `onBeforeSceneUnload` | 再 Run / 卸场景前 |
|
|
63
|
+
| `onDispose` | 应用拆除;引擎不 destroy,下次 Run 复用 |
|
|
64
|
+
|
|
65
|
+
本地预览只有当前这一份场景,`ctx.sceneManager.loadScene` 会 reject。`ctx.assets.text/json` 读工作区相对路径。从 `ctx.engine` 取引擎,不要再 `RuntimeEngine.create`。
|
|
29
66
|
|
|
30
|
-
`
|
|
67
|
+
1. 若还没有类型:运行 `easytwin skills sync`(无 tsconfig 会生成最小配置,含 `@easytwin/runtime` 与 `@easytwin/apps` 的 paths;已有 tsconfig 时按输出片段自行添加)。
|
|
68
|
+
2. 编译校验:`easytwin bundle`。lodash 等外部依赖会报错。超出在线 stub 的 runtime import 只 warning。
|
|
69
|
+
3. 运行:打开插件场景预览(先看到三维场景),点底部 **Run**。再点 Run 会先 `onBeforeSceneUnload` / `onDispose`,复用同一台引擎。编译失败不打断已渲染场景;mock 下同样可用。
|
|
31
70
|
|
|
32
|
-
|
|
71
|
+
`Component` / `VirtualRootComponent` 等整包 API 本地预览可用,但**不是**可上传子集;需要组件生命周期细节时读 `references/lifecycle-events.md`。
|
|
33
72
|
|
|
34
73
|
## 参考(references/)
|
|
35
74
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# 引入与初始化
|
|
2
2
|
|
|
3
|
+
## TwinApp 里如何拿到引擎
|
|
4
|
+
|
|
5
|
+
用户代码入口是 `src/main.ts` 的 `export default class App extends TwinApp`。预览页 / 在线环境已经创建引擎并加载场景;钩子里用 `ctx.engine` / `ctx.container` / `ctx.scene`。可上传子集只用 `THREE` / `RuntimeEngine` / `SceneManager` / `LoadSceneMode` / `convertObjToComponentJson`。
|
|
6
|
+
|
|
3
7
|
## 包信息
|
|
4
8
|
|
|
5
|
-
- npm 包名:`@easytwin/runtime`(商业包,公网不存在)
|
|
6
|
-
-
|
|
9
|
+
- npm 包名:`@easytwin/runtime`(商业包,公网不存在)。类型由 `easytwin skills sync` 写入 `.easytwin/types/`,运行走预览页 Run 或 `easytwin bundle`。
|
|
10
|
+
- `TwinApp` / `defineApp` / `TwinAppContext` 从 `@easytwin/apps` 引入(同样由 sync 分发)。
|
|
7
11
|
|
|
8
|
-
##
|
|
12
|
+
## RuntimeEngine.create(宿主调用)
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
工厂方法:`RuntimeEngine.create(config)`(静态、异步)。TwinApp 从 `ctx.engine` 取用已创建的实例。
|
|
11
15
|
|
|
12
16
|
```ts
|
|
13
17
|
import { RuntimeEngine, SceneManager, LoadSceneMode } from "@easytwin/runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 场景加载与资产
|
|
2
2
|
|
|
3
|
-
> 说明:本节讲的是 runtime 的场景 JSON(组件树序列化结构,`SceneJson`,定义见 `src/core/interface.ts`)与资产加载。`easytwin scene pull` 拉取的服务端场景 JSON 同样以该结构为准(见 easytwin-scene)
|
|
3
|
+
> 说明:本节讲的是 runtime 的场景 JSON(组件树序列化结构,`SceneJson`,定义见 `src/core/interface.ts`)与资产加载。`easytwin scene pull` 拉取的服务端场景 JSON 同样以该结构为准(见 easytwin-scene)。TwinApp 场景由宿主加载;本地预览里 `ctx.sceneManager.loadScene` 会 reject。下面是 SceneManager 内部 API。
|
|
4
4
|
|
|
5
5
|
## 场景管理(SceneManager)
|
|
6
6
|
|
|
@@ -5,8 +5,8 @@ description: 当用户要列出场景、查看有哪些场景、或把某个场
|
|
|
5
5
|
|
|
6
6
|
# 场景管理
|
|
7
7
|
|
|
8
|
-
- `easytwin scene list
|
|
9
|
-
- `easytwin scene pull <id> [--out <path>]
|
|
8
|
+
- `easytwin scene list`:列出 SDK 应用已关联的场景(id 为 Scene Key),并把摘要(id / name / linkedSceneId / snapshotUrl / defaultLoading)写入项目 `easytwin.config.json` 的 `scenes` 数组(全量覆盖,不含场景 JSON)。
|
|
9
|
+
- `easytwin scene pull <id> [--out <path>]`:按 Scene Key(或关联记录 id)拉取场景快照 JSON 到本地,缺省输出 `./<id>.scene.json`。
|
|
10
10
|
|
|
11
11
|
## 场景 JSON 格式
|
|
12
12
|
|
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: easytwin-upload
|
|
3
|
-
description: 当用户要把本地开发产物目录上传回 EasyTwin
|
|
3
|
+
description: 当用户要把本地开发产物目录上传回 EasyTwin、从服务端拉取工作区代码、远端没有代码时创建默认文件、或询问上传是否可逆/与本地 diff 如何同步时使用。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# 工作区代码:拉取与全量上传
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
上传与拉取共用同一套工作区代码接口,方向相反。
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## 拉取:`easytwin pull [dir]`
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
从服务端下载 App ID 对应的工作区文件到 `[dir]`(缺省当前目录)。
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
14
|
+
- 远端为空:本地没有 `src/main.ts` 时写入默认 TwinApp 子类入口;本地已有入口则不覆盖。
|
|
15
|
+
- 远端有文件:与本地做 diff。`identical` 跳过,`remote-only` 写入,`local-only` 保留,**内容冲突默认不覆盖**。
|
|
16
|
+
- `--force` 才用远端内容覆盖冲突文件;即使 `--force` 也不删除仅本地文件。
|
|
17
|
+
- `--dry-run` 只打印 diff,不写盘。
|
|
18
|
+
- 本地测试模式(`appId`/`appSecret` 均为 `test`):不发请求,按远端为空处理。
|
|
19
|
+
|
|
20
|
+
有冲突时先看摘要,确认要用远端覆盖再加 `--force`。插件里可对冲突文件打开「远程 ↔ 本地」diff。
|
|
21
|
+
|
|
22
|
+
## 上传:`easytwin upload <dir>`
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
把 `<dir>` 下的全部文件上传,按 App ID 决定的目标空间**全量覆盖**。
|
|
25
|
+
|
|
26
|
+
> ⚠️ **覆盖不可逆**:上传会覆盖服务端同名内容,没有本地清单与回滚机制。上传前务必确认目录内容与目标空间。
|
|
27
|
+
|
|
28
|
+
- 递归收集 `<dir>` 下所有文件(默认跳过 `.git`)。
|
|
29
|
+
- 按工作区代码文件接口全量覆盖:先拉远端文件列表与约束(扩展名/数量/目录深度),再删除远端多余文件、批量更新变更、逐个新建缺失文件。
|
|
30
|
+
- 上传目标空间由凭据(App ID)决定;场景 pull 与工作区 pull/upload 是独立能力,互不引用。
|
|
19
31
|
|
|
20
|
-
当 `appId` 与 `appSecret` 均为 `test` 时,`easytwin upload <dir>` 退化为本地空跑(dry-run)
|
|
32
|
+
当 `appId` 与 `appSecret` 均为 `test` 时,`easytwin upload <dir>` 退化为本地空跑(dry-run):只收集与统计文件、不上传,进度照常上报,输出标注「本地测试模式」。
|
|
21
33
|
|
|
22
34
|
## 步骤
|
|
23
35
|
|
|
24
|
-
1.
|
|
25
|
-
2.
|
|
36
|
+
1. 新项目或本地还没有代码:`easytwin pull`(远端空则得到默认 `src/main.ts`)。
|
|
37
|
+
2. 本地已有改动且可能与远端不同:`easytwin pull --dry-run` 看 diff,再决定是否 `--force`。
|
|
38
|
+
3. 确认目标空间(App ID)与目录内容后,`easytwin upload <dir>` 上传(不可逆)。
|