@chanlerdev/scorel 0.0.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.
- package/README.md +110 -0
- package/dist/index.js +6675 -0
- package/dist/index.js.map +7 -0
- package/docs/CHANGELOG.md +12 -0
- package/docs/README.md +116 -0
- package/docs/ROADMAP.md +669 -0
- package/docs/SHIP.md +242 -0
- package/docs/spec/channels.md +156 -0
- package/docs/spec/client.md +326 -0
- package/docs/spec/daemon.md +408 -0
- package/docs/spec/events.md +423 -0
- package/docs/spec/extensions.md +255 -0
- package/docs/spec/relay.md +391 -0
- package/docs/spec/runtime.md +251 -0
- package/docs/spec/session.md +380 -0
- package/docs/spec/ship/S0001-docs-baseline.md +41 -0
- package/docs/spec/ship/S0002-package-skeleton.md +56 -0
- package/docs/spec/ship/S0003-protocol-contracts.md +49 -0
- package/docs/spec/ship/S0004-session-core.md +50 -0
- package/docs/spec/ship/S0005-runtime-loop.md +48 -0
- package/docs/spec/ship/S0006-embedded-daemon-client.md +51 -0
- package/docs/spec/ship/S0007-cli-alpha.md +49 -0
- package/docs/spec/ship/S0008-coding-tools.md +107 -0
- package/docs/spec/ship/S0009-code-discovery-tools.md +82 -0
- package/docs/spec/ship/S0010-todo-tool-and-cli.md +81 -0
- package/docs/spec/ship/S0011-coding-agent-alpha-smoke.md +110 -0
- package/docs/spec/ship/S0012-coding-tools-maturity.md +143 -0
- package/docs/spec/ship/S0013-local-daemon-protocol.md +57 -0
- package/docs/spec/ship/S0014-local-daemon-lifecycle.md +64 -0
- package/docs/spec/ship/S0015-local-attach-and-broadcast.md +58 -0
- package/docs/spec/ship/S0016-local-daemon-resync-smoke.md +60 -0
- package/docs/spec/ship/S0017-grep-files-output-mode.md +49 -0
- package/docs/spec/ship/S0018-daemon-entrypoint-smoke.md +48 -0
- package/docs/spec/ship/S0019-remote-transport-contract.md +59 -0
- package/docs/spec/ship/S0020-remote-websocket-server.md +56 -0
- package/docs/spec/ship/S0021-remote-websocket-client-transport.md +55 -0
- package/docs/spec/ship/S0022-remote-daemon-cli-lifecycle.md +60 -0
- package/docs/spec/ship/S0023-remote-control-e2e-validation.md +66 -0
- package/docs/spec/ship/S0024-remote-attach-interactive-stream.md +49 -0
- package/docs/spec/ship/S0025-remote-attach-session-event-view.md +57 -0
- package/docs/spec/ship/S0026-attach-project-cache-and-dual-seq-reconnect.md +87 -0
- package/docs/spec/ship/S0027-session-diagnostics-log.md +77 -0
- package/docs/spec/ship/S0028-client-attach-diagnostics-log.md +70 -0
- package/docs/spec/ship/S0029-project-index-for-session-lookup.md +119 -0
- package/docs/spec/ship/S0030-webui-product-intent.md +73 -0
- package/docs/spec/ship/S0031-daemon-projectslug-rule.md +72 -0
- package/docs/spec/ship/S0032-daemon-protocol-completion.md +123 -0
- package/docs/spec/ship/S0033-webui-skeleton-routing.md +92 -0
- package/docs/spec/ship/S0034-webui-device-settings.md +121 -0
- package/docs/spec/ship/S0035-webui-device-handshake.md +83 -0
- package/docs/spec/ship/S0036-webui-project-session-sync.md +70 -0
- package/docs/spec/ship/S0037-webui-chatbox-v1.md +97 -0
- package/docs/spec/ship/S0038-webui-cancel-multiclient.md +65 -0
- package/docs/spec/ship/S0039-webui-e2e-newchat.md +74 -0
- package/docs/spec/ship/S0040-webui-codex-visual-tokens.md +227 -0
- package/docs/spec/ship/S0041-webui-markdown-and-tool-block.md +248 -0
- package/docs/spec/ship/S0042-webui-streaming-ux-autoscroll.md +130 -0
- package/docs/spec/ship/S0043-startup-ergonomics.md +278 -0
- package/docs/spec/ship/S0044-webui-chatbox-rebuild.md +556 -0
- package/docs/spec/ship/S0045-webui-card-sidebar-and-session-fixes.md +469 -0
- package/docs/spec/ship/S0046-webui-empty-composer-and-lazy-session.md +428 -0
- package/docs/spec/ship/S0047-webui-project-hover-newchat-and-dynamic-greeting.md +176 -0
- package/docs/spec/ship/S0048-device-level-host-project-registry.md +253 -0
- package/docs/spec/ship/S0049-webui-add-project-directory-browser.md +217 -0
- package/docs/spec/ship/S0050-instruction-snapshot-and-agents-assembly.md +338 -0
- package/docs/spec/ship/S0051-harness-item-and-system-reminder.md +190 -0
- package/docs/spec/ship/S0052-follow-up-queue-and-dual-loop.md +195 -0
- package/docs/spec/ship/S0053-skill-index-and-skill-tool.md +252 -0
- package/docs/spec/ship/S0054-webui-running-message-behavior.md +72 -0
- package/docs/spec/ship/S0055-webui-composer-acceptance-and-queue-strip.md +68 -0
- package/docs/spec/ship/S0056-relay-and-hosted-webui-contract.md +106 -0
- package/docs/spec/ship/S0057-relay-service-protocol-skeleton.md +161 -0
- package/docs/spec/ship/S0058-host-outbound-relay-and-pair-command.md +138 -0
- package/docs/spec/ship/S0059-relay-transport-and-hosted-webui-connector.md +140 -0
- package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.md +132 -0
- package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.verification.md +90 -0
- package/docs/spec/ship/S0061-hosted-defaults-and-cli-command-surface.md +208 -0
- package/docs/spec/ship/S0062-npm-package-and-release-workflow.md +166 -0
- package/docs/spec/tools.md +173 -0
- package/package.json +51 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# Daemon Host - Device-level Runtime And Project Coordination
|
|
2
|
+
|
|
3
|
+
> 上游:`architecture.md`、`decisions/006-device-host-project-registry.md`、`spec/events.md`、`spec/runtime.md`
|
|
4
|
+
> 归属包:`@scorel/daemon`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 0. 定位
|
|
9
|
+
|
|
10
|
+
Scorel daemon 是 **Device-level Host**:
|
|
11
|
+
|
|
12
|
+
- 一台 Device 默认运行一个 Host。
|
|
13
|
+
- 一个 Host 管理多个 Project。
|
|
14
|
+
- Host 是 Runtime 和 Session JSONL 的唯一持有者与写入者。
|
|
15
|
+
- CLI、WebUI、GUI、IM 和未来 HTTP API 都不能绕过 Host。
|
|
16
|
+
|
|
17
|
+
对外命令和包名继续使用 `daemon`。代码实现可将当前 `EmbeddedDaemon` 重命名为 `ScorelHost`,避免继续暗示“一 daemon 一 cwd”。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. 不变量
|
|
22
|
+
|
|
23
|
+
1. Host 身份是 `deviceId`,不是 cwd。
|
|
24
|
+
2. Project 是正式实体,持久化到 `~/.scorel/projects.json`。
|
|
25
|
+
3. 每个 Project 有 Host 生成的稳定 `projectId`。
|
|
26
|
+
4. 每个 Session header 必须持久化 `projectId`。
|
|
27
|
+
5. Runtime 创建时必须通过 `session.meta.projectId` 查询 Registry,再取得 canonical `workDir`。
|
|
28
|
+
6. Project 可以没有 Session;因此 `list_projects` 不得由 Session JSONL 聚合替代。
|
|
29
|
+
7. Session JSONL 只有 Host 可以写。
|
|
30
|
+
8. PersistentEvent 与 TransientEvent 共用 per-session seq。
|
|
31
|
+
9. 当前 pre-1.0 不保留 `projectSlug`、`workDirHint` 或旧本地状态兼容层。
|
|
32
|
+
|
|
33
|
+
关键验收:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
Project A -> Session A -> Runtime cwd A
|
|
37
|
+
Project B -> Session B -> Runtime cwd B
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
同一 Host 下两个 Session 必须能在两个不同真实仓库中执行工具,不能串 cwd。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2. 领域模型
|
|
45
|
+
|
|
46
|
+
### 2.1 IDs
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
type ProjectId = Brand<string, "ProjectId">;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2.2 Project
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
type HostProject = {
|
|
56
|
+
projectId: ProjectId;
|
|
57
|
+
displayName: string;
|
|
58
|
+
workDir: string; // canonical absolute path
|
|
59
|
+
createdAt: number;
|
|
60
|
+
updatedAt: number;
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
规则:
|
|
65
|
+
|
|
66
|
+
- `projectId` 由 Host 生成,例如 `prj_<uuid>`。
|
|
67
|
+
- `workDir` 在注册时 canonicalize,并由 owning Host 持久化。
|
|
68
|
+
- 相同 canonical `workDir` 重复注册必须返回已有 Project,不能创建重复项。
|
|
69
|
+
- `displayName` 默认取 `basename(workDir)`,以后可允许重命名。
|
|
70
|
+
- 删除 Project 不自动删除 Session JSONL;S0048 只允许删除没有 Session 的 Project,避免隐式数据删除。
|
|
71
|
+
|
|
72
|
+
### 2.3 Session Meta
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
type SessionMeta = {
|
|
76
|
+
projectId: ProjectId;
|
|
77
|
+
title?: string;
|
|
78
|
+
model?: string;
|
|
79
|
+
createdAt?: number;
|
|
80
|
+
updatedAt?: number;
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`projectId` 是 Session 与 Runtime cwd 的唯一绑定。不得允许 client 提交 cwd 作为 `create_session` 的旁路参数。
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 3. Host 结构
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
ScorelHost
|
|
92
|
+
├── DeviceIdentity
|
|
93
|
+
├── ProjectRegistry
|
|
94
|
+
├── SessionStore
|
|
95
|
+
├── RuntimePool
|
|
96
|
+
├── EventHub
|
|
97
|
+
├── ConnectionManager
|
|
98
|
+
├── ChannelManager
|
|
99
|
+
└── TransportAdapters
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3.1 ProjectRegistry
|
|
103
|
+
|
|
104
|
+
持久化:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
~/.scorel/projects.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
文件形态:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
type ProjectRegistryFile = {
|
|
114
|
+
version: 1;
|
|
115
|
+
projects: HostProject[];
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
API:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
interface ProjectRegistry {
|
|
123
|
+
list(): Promise<HostProject[]>;
|
|
124
|
+
get(projectId: ProjectId): Promise<HostProject | undefined>;
|
|
125
|
+
require(projectId: ProjectId): Promise<HostProject>;
|
|
126
|
+
register(workDir: string): Promise<HostProject>;
|
|
127
|
+
remove(projectId: ProjectId): Promise<void>;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 3.2 RuntimePool
|
|
132
|
+
|
|
133
|
+
每个活跃 Session 最多一个 Runtime:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
type SessionLane = {
|
|
137
|
+
session: JsonlSession;
|
|
138
|
+
project: HostProject;
|
|
139
|
+
runtime: ScorelRuntime;
|
|
140
|
+
queue: Promise<unknown>;
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Runtime factory 改为 project-aware:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
type RuntimeFactory = (input: {
|
|
148
|
+
sessionId: SessionId;
|
|
149
|
+
project: HostProject;
|
|
150
|
+
}) => Promise<ScorelRuntime>;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
真实 runtime 创建流程:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
project.workDir
|
|
157
|
+
-> loadScorelConfig({ cwd: project.workDir })
|
|
158
|
+
-> createCodingTools({ cwd: project.workDir })
|
|
159
|
+
-> createPiAiProvider(...)
|
|
160
|
+
-> ScorelRuntime
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3.3 SessionStore
|
|
164
|
+
|
|
165
|
+
继续使用 flat 目录:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
~/.scorel/sessions/<sessionId>.jsonl
|
|
169
|
+
~/.scorel/sessions/<sessionId>.log
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
不需要把文件搬入 Project 子目录。Session header 中的 `projectId` 足以索引归属。
|
|
173
|
+
|
|
174
|
+
### 3.4 EventHub
|
|
175
|
+
|
|
176
|
+
- per-session seq。
|
|
177
|
+
- PersistentEvent 写 JSONL 后广播。
|
|
178
|
+
- TransientEvent 只广播并进入 live buffer。
|
|
179
|
+
- reconnect 使用 dual-seq:
|
|
180
|
+
- `stream_resume`
|
|
181
|
+
- `persistent_fallback`
|
|
182
|
+
- `full_reload`
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 4. Host API
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
interface ScorelHost {
|
|
190
|
+
start(): Promise<void>;
|
|
191
|
+
shutdown(): Promise<void>;
|
|
192
|
+
|
|
193
|
+
listDirectories(path?: string): Promise<DirectoryListing>;
|
|
194
|
+
registerProject(workDir: string): Promise<HostProject>;
|
|
195
|
+
listProjects(): Promise<HostProject[]>;
|
|
196
|
+
removeProject(projectId: ProjectId): Promise<void>;
|
|
197
|
+
|
|
198
|
+
createSession(meta: SessionMeta): Promise<SessionId>;
|
|
199
|
+
loadSession(sessionId: SessionId): Promise<SessionLane>;
|
|
200
|
+
getRuntime(sessionId: SessionId): ScorelRuntime | undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
type DirectoryEntry = {
|
|
204
|
+
name: string;
|
|
205
|
+
path: string;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
type DirectoryListing = {
|
|
209
|
+
path: string;
|
|
210
|
+
parentPath?: string;
|
|
211
|
+
entries: DirectoryEntry[];
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
当前可信用户模型允许完整目录浏览。`listDirectories()` 不做 ACL 或根目录限制,但必须:
|
|
217
|
+
|
|
218
|
+
- 只返回目录,不返回文件内容。
|
|
219
|
+
- 对不存在、无权限、非目录路径返回结构化错误。
|
|
220
|
+
- 使用 canonical absolute path。
|
|
221
|
+
- 稳定排序:目录名 locale compare。
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 5. Wire Protocol
|
|
226
|
+
|
|
227
|
+
### 5.1 Project 请求
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
type ClientRequestMap = {
|
|
231
|
+
list_directories: {
|
|
232
|
+
request: { path?: string };
|
|
233
|
+
response: { path: string; parentPath?: string; entries: DirectoryEntry[] };
|
|
234
|
+
};
|
|
235
|
+
register_project: {
|
|
236
|
+
request: { workDir: string };
|
|
237
|
+
response: { project: HostProject };
|
|
238
|
+
};
|
|
239
|
+
list_projects: {
|
|
240
|
+
request: {};
|
|
241
|
+
response: { projects: HostProject[] };
|
|
242
|
+
};
|
|
243
|
+
remove_project: {
|
|
244
|
+
request: { projectId: ProjectId };
|
|
245
|
+
response: { projectId: ProjectId; removed: boolean };
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 5.2 Session 请求
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
type ClientRequestMap = {
|
|
254
|
+
create_session: {
|
|
255
|
+
request: {
|
|
256
|
+
sessionId?: SessionId;
|
|
257
|
+
meta: { projectId: ProjectId; title?: string; model?: string };
|
|
258
|
+
};
|
|
259
|
+
response: { sessionId: SessionId };
|
|
260
|
+
};
|
|
261
|
+
list_sessions: {
|
|
262
|
+
request: { projectId?: ProjectId; limit?: number };
|
|
263
|
+
response: { sessions: SessionSummary[] };
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`create_session` 必须拒绝:
|
|
269
|
+
|
|
270
|
+
- 缺少 `projectId`。
|
|
271
|
+
- `projectId` 不存在。
|
|
272
|
+
- client 试图直接提交 cwd。
|
|
273
|
+
|
|
274
|
+
### 5.3 Connection Identity
|
|
275
|
+
|
|
276
|
+
Handshake 只报告 Device 身份:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
type ConnectResult = {
|
|
280
|
+
clientId: ClientId;
|
|
281
|
+
sessionId?: SessionId;
|
|
282
|
+
currentSeq?: Seq;
|
|
283
|
+
deviceId: DeviceId;
|
|
284
|
+
deviceDisplayName?: string;
|
|
285
|
+
};
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Project 不属于 connection identity。Client 通过 `list_projects` 获取 Project 列表。
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 6. Transport
|
|
293
|
+
|
|
294
|
+
| Transport | 状态 | 场景 |
|
|
295
|
+
|---|---|---|
|
|
296
|
+
| Embedded | 已有 | `scorel chat` 临时 Host |
|
|
297
|
+
| WebSocket | 已有 | `scorel host serve`、WebUI、Direct WS |
|
|
298
|
+
| SSH stdio proxy | 后续 | GUI 远端 Device |
|
|
299
|
+
| HTTP + SSE | 后续 | 纯 API |
|
|
300
|
+
|
|
301
|
+
S0043 已删除 Unix socket transport。不要重新引入旧 socket 路径作为兼容层。
|
|
302
|
+
|
|
303
|
+
### 6.1 SSH Proxy 边界
|
|
304
|
+
|
|
305
|
+
后续 `scorel proxy`:
|
|
306
|
+
|
|
307
|
+
- 通过 SSH stdio 转发到远端 Host control endpoint。
|
|
308
|
+
- 不持有 Project。
|
|
309
|
+
- 不持有 Session。
|
|
310
|
+
- 不创建 Runtime。
|
|
311
|
+
- 不复制业务协议。
|
|
312
|
+
|
|
313
|
+
### 6.2 HTTP 边界
|
|
314
|
+
|
|
315
|
+
后续 HTTP adapter:
|
|
316
|
+
|
|
317
|
+
- REST 负责 command。
|
|
318
|
+
- SSE 负责 event stream。
|
|
319
|
+
- handler 调用同一 Host application service。
|
|
320
|
+
- 不直接读写 JSONL。
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 7. Entry 场景
|
|
325
|
+
|
|
326
|
+
### 7.1 CLI Embedded
|
|
327
|
+
|
|
328
|
+
```text
|
|
329
|
+
cd /repo
|
|
330
|
+
scorel
|
|
331
|
+
-> create temporary Host
|
|
332
|
+
-> registry.register(/repo)
|
|
333
|
+
-> createSession({ projectId })
|
|
334
|
+
-> DaemonClient over EmbeddedTransport
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 7.2 Local WebUI
|
|
338
|
+
|
|
339
|
+
```text
|
|
340
|
+
scorel up
|
|
341
|
+
-> persistent WS Host
|
|
342
|
+
-> WebUI detects local Device
|
|
343
|
+
-> Add Project
|
|
344
|
+
-> listDirectories + registerProject
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 7.3 Remote WebUI
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
WebUI
|
|
351
|
+
-> connect Device URL + token
|
|
352
|
+
-> Add Project
|
|
353
|
+
-> browse remote Host directories
|
|
354
|
+
-> registerProject
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### 7.4 GUI
|
|
358
|
+
|
|
359
|
+
```text
|
|
360
|
+
Local Folder Picker
|
|
361
|
+
-> local Host.registerProject
|
|
362
|
+
|
|
363
|
+
SSH Device
|
|
364
|
+
-> scorel proxy
|
|
365
|
+
-> remote Host.listDirectories
|
|
366
|
+
-> remote Host.registerProject
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 8. Diagnostics
|
|
372
|
+
|
|
373
|
+
每个 Session 保留同目录 `.log`:
|
|
374
|
+
|
|
375
|
+
```text
|
|
376
|
+
~/.scorel/sessions/<sessionId>.log
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
需要记录:
|
|
380
|
+
|
|
381
|
+
- `project_registered`
|
|
382
|
+
- `project_removed`
|
|
383
|
+
- `session_created` + `projectId`
|
|
384
|
+
- `session_loaded` + `projectId`
|
|
385
|
+
- `runtime_created` + `projectId` + `workDir`
|
|
386
|
+
- connect/disconnect
|
|
387
|
+
- resync mode
|
|
388
|
+
- provider/runtime errors
|
|
389
|
+
|
|
390
|
+
不得记录 token、API key、SSH password 或私钥内容。
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## 9. 开发期破坏性重构
|
|
395
|
+
|
|
396
|
+
S0048 直接执行:
|
|
397
|
+
|
|
398
|
+
- 删除 `projectSlug` 和 `workDirHint` wire/schema。
|
|
399
|
+
- 删除 Session header 中旧 Project 字段。
|
|
400
|
+
- 删除从 JSONL 聚合 Project 的 `ProjectAggregator`。
|
|
401
|
+
- `protocolVersion` 增加。
|
|
402
|
+
- 本地开发环境需要清理旧 `~/.scorel/project-index.json`、旧 Session JSONL、旧 attach cache 和浏览器 localStorage。新的 `~/.scorel/projects.json` 由 Registry 创建。
|
|
403
|
+
|
|
404
|
+
不写迁移器,不保留 fallback。
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
*Host 的职责不是守住一个 cwd,而是守住一台 Device 上的 Project、Session 和 Runtime 一致性。*
|