@chanlerdev/scorel 0.0.4 → 0.0.6
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 +37 -1
- package/dist/index.js +676 -198
- package/dist/index.js.map +4 -4
- package/docs/CHANGELOG.md +73 -0
- package/docs/ROADMAP.md +11 -0
- package/docs/SHIP.md +10 -5
- package/docs/spec/events.md +17 -1
- package/docs/spec/session.md +12 -0
- package/docs/spec/ship/S0064-gui-product-intent-and-boundary.md +1 -1
- package/docs/spec/ship/S0073-provider-model-profile-contract.md +8 -1
- package/docs/spec/ship/S0103-daemon-lifecycle-and-settings-resilience.md +61 -0
- package/docs/spec/ship/S0104-tool-result-artifacts.md +64 -0
- package/docs/spec/ship/S0105-cli-update-and-gui-release.md +128 -0
- package/docs/spec/ship/S0106-snip-context-control.md +113 -0
- package/docs/spec/ship/S0107-system-reminder-unification.md +112 -0
- package/docs/spec/ship/S0108-gui-bundled-cli-runtime.md +108 -0
- package/package.json +1 -1
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.0.6 - 2026-06-23
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- Packed GUI now bundles its own CLI runtime, enabling fully self-contained local Host startup without Node.js or global CLI.
|
|
10
|
+
- Agents can now use the `snip` tool to hide completed user turns from future context — reducing token waste and keeping conversations focused.
|
|
11
|
+
|
|
12
|
+
### Changes
|
|
13
|
+
|
|
14
|
+
- GUI now bundles its own CLI runtime for fully self-contained Host startup (no Node.js or global CLI required).
|
|
15
|
+
- Added `snip` tool that agents can call to mark a completed user turn as hidden from future LLM context.
|
|
16
|
+
- Protocol version incremented to 4 with new `context_control` event and `hide_user_turn` operation.
|
|
17
|
+
- UI (GUI and WebUI) now hides model-only text blocks (like `snip` reminders) from the visible transcript.
|
|
18
|
+
- Provider adapters now pass each tool's own parameter schema instead of hardcoding tool-specific parameters.
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
|
|
22
|
+
- Increased Host startup timeout from 10s to 30s to prevent timeouts in slower development environments.
|
|
23
|
+
|
|
24
|
+
### Breaking Changes
|
|
25
|
+
|
|
26
|
+
- Protocol version incremented from 3 to 4; requires protocol-version-aware clients.
|
|
27
|
+
- Packaged GUI no longer accepts `SCOREL_CLI_ENTRYPOINT` or `SCOREL_NODE_PATH` environment variables.
|
|
28
|
+
|
|
29
|
+
### Verification
|
|
30
|
+
|
|
31
|
+
- Unit and release tests verify bundled CLI usage in packaged GUI, snip tool end-to-end behavior, hidden spans in context builds, protocol version bump, and UI projector rendering.
|
|
32
|
+
|
|
33
|
+
### Internal
|
|
34
|
+
|
|
35
|
+
- Added planned spec S0107 for system reminder unification (documentation only).
|
|
36
|
+
|
|
37
|
+
## 0.0.5 - 2026-06-19
|
|
38
|
+
|
|
39
|
+
### Highlights
|
|
40
|
+
|
|
41
|
+
- New CLI commands `scorel version`, `scorel update`, and `scorel upgrade` for software lifecycle management.
|
|
42
|
+
- Oversized Bash tool output is now archived to session artifacts, returning compact head/tail projections to the model.
|
|
43
|
+
- GUI auto-update support with macOS DMG/ZIP packaging and incremental updates.
|
|
44
|
+
|
|
45
|
+
### Changes
|
|
46
|
+
|
|
47
|
+
- GUI and daemon now honor the selected chat model when sending messages.
|
|
48
|
+
- GUI settings are more resilient: ignore stale device responses, error boundaries on settings sections, and fixed state reset when switching devices.
|
|
49
|
+
- `scorel host serve` and `scorel host start` no longer idle-timeout by default; only convenience daemons (GUI auto-start, `scorel up`) enforce a 15-minute idle timeout.
|
|
50
|
+
- GUI auto-start uses an ephemeral port to avoid conflicts with user-started daemons.
|
|
51
|
+
|
|
52
|
+
### Fixes
|
|
53
|
+
|
|
54
|
+
- GUI provider model selection now persists correctly across profile refreshes and session creation.
|
|
55
|
+
- Daemon lifecycle hardened: foreground daemon stays alive until Ctrl+C/SIGTERM.
|
|
56
|
+
|
|
57
|
+
### Verification
|
|
58
|
+
|
|
59
|
+
- Unit tests for update helpers (semver comparison, npm check/install, auto-update gate).
|
|
60
|
+
- Unit tests for GUI main process (electron-updater import, manual update item, tray setup).
|
|
61
|
+
- Integration test for release asset collection and version lockstep.
|
|
62
|
+
- Tests for oversized Bash archive and projection logic.
|
|
63
|
+
- Tests for daemon idle timeout behavior.
|
|
64
|
+
- Tests for GUI settings resilience (stale data, error boundary, state reset).
|
|
65
|
+
- Tests for model selection fallback and normalization.
|
|
66
|
+
|
|
67
|
+
### Internal
|
|
68
|
+
|
|
69
|
+
- Update SHIP.md to clarify that small bug fixes may skip spec requirement; only changes affecting stable contracts or user-visible direction need a spec.
|
|
70
|
+
- Oversized Bash results are written to session-scoped artifacts, excluded from diagnostics and Relay.
|
|
71
|
+
|
|
72
|
+
- Add `scorel version`, `scorel update`, and `scorel upgrade`.
|
|
73
|
+
- Add hourly Host auto-update checks gated by active work state.
|
|
74
|
+
- Add GUI macOS release packaging and Electron updater metadata to the release path.
|
|
75
|
+
- Add GUI application menu and macOS status bar menu entries for manual update checks and common app actions.
|
|
76
|
+
- Document unsigned macOS GUI quarantine bypass command.
|
|
77
|
+
|
|
5
78
|
## 0.0.4 - 2026-06-14
|
|
6
79
|
|
|
7
80
|
### Highlights
|
package/docs/ROADMAP.md
CHANGED
|
@@ -598,6 +598,11 @@ M5 WebUI 的正式产品方向记录在 [`S0030`](spec/ship/S0030-webui-product-
|
|
|
598
598
|
| M9.F1.22 | [`S0100`](spec/ship/S0100-gui-provider-danger-zone.md) | GUI Provider 删除按钮位置初版 | Done |
|
|
599
599
|
| M9.F1.23 | [`S0101`](spec/ship/S0101-gui-device-settings-polish.md) | GUI Settings 改为设备级配置,修正 Provider 删除位置、Token 文案、设备展开/重命名交互 | Done |
|
|
600
600
|
| M9.F1.24 | [`S0102`](spec/ship/S0102-device-only-config.md) | Config 彻底收敛为设备级唯一配置,移除 Project config 运行时语义 | Done |
|
|
601
|
+
| M9.F1.25 | [`S0103`](spec/ship/S0103-daemon-lifecycle-and-settings-resilience.md) | Daemon 生命周期按入口区分,并修复 GUI Settings remote 切换黑屏风险 | Done |
|
|
602
|
+
| M9.F1.26 | [`S0105`](spec/ship/S0105-cli-update-and-gui-release.md) | CLI 命令面统一补齐、NPM 手动/自动更新、GUI release 打包和增量更新框架 | Done |
|
|
603
|
+
| M9.F1.27 | [`S0106`](spec/ship/S0106-snip-context-control.md) | `context_control` 持久事件和 `snip` tool,让 agent 隐藏已完成 user turn 的未来 LLM context 投影 | Done |
|
|
604
|
+
| M9.F1.28 | [`S0107`](spec/ship/S0107-system-reminder-unification.md) | 统一 system reminder 的持久化、构造、LLM 投影和 UI visibility 语义 | Planned |
|
|
605
|
+
| M9.F1.29 | [`S0108`](spec/ship/S0108-gui-bundled-cli-runtime.md) | GUI release 内置同版本 CLI runtime,packaged GUI 用 bundle 内可执行文件启动本地 Host | Active |
|
|
601
606
|
|
|
602
607
|
**Not in M9 Follow-up**:
|
|
603
608
|
|
|
@@ -774,6 +779,12 @@ HTTP adapter 必须映射已有 Host use cases,不复制领域逻辑。
|
|
|
774
779
|
| [`S0100`](spec/ship/S0100-gui-provider-danger-zone.md) | GUI Provider danger-zone placement | Done |
|
|
775
780
|
| [`S0101`](spec/ship/S0101-gui-device-settings-polish.md) | GUI device-scoped Settings polish | Done |
|
|
776
781
|
| [`S0102`](spec/ship/S0102-device-only-config.md) | Device-only config | Done |
|
|
782
|
+
| [`S0103`](spec/ship/S0103-daemon-lifecycle-and-settings-resilience.md) | Daemon lifecycle and Settings resilience | Done |
|
|
783
|
+
| [`S0104`](spec/ship/S0104-tool-result-artifacts.md) | Tool result artifacts for oversized Bash output | Done |
|
|
784
|
+
| [`S0105`](spec/ship/S0105-cli-update-and-gui-release.md) | CLI update and GUI release | Done |
|
|
785
|
+
| [`S0106`](spec/ship/S0106-snip-context-control.md) | Snip context control | Done |
|
|
786
|
+
| [`S0107`](spec/ship/S0107-system-reminder-unification.md) | System reminder unification | Planned |
|
|
787
|
+
| [`S0108`](spec/ship/S0108-gui-bundled-cli-runtime.md) | GUI bundled CLI runtime | Active |
|
|
777
788
|
|
|
778
789
|
---
|
|
779
790
|
|
package/docs/SHIP.md
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
```bash
|
|
26
26
|
pnpm install
|
|
27
27
|
pnpm scorel # 在当前目录进入交互式项目会话
|
|
28
|
+
pnpm scorel --version
|
|
29
|
+
pnpm scorel update
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
Hosted WebUI 路径:
|
|
@@ -35,7 +37,7 @@ open https://scorel.chanler.dev
|
|
|
35
37
|
pnpm scorel pair <pair-code>
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
`scorel host serve` 会以前台调试模式启动本机 Host、注册当前目录为初始 Project,并默认连接官方 Relay
|
|
40
|
+
`scorel host serve` 会以前台调试模式启动本机 Host、注册当前目录为初始 Project,并默认连接官方 Relay;前台 Host 默认一直存活,直到 Ctrl+C / SIGTERM,除非显式传入 `--idle-timeout-ms`。`scorel host start` 会启动或复用后台 singleton Host,并返回到 shell;直接后台启动的 CLI Host 默认一直存活,直到 `scorel host stop` 或进程退出。`scorel up` / `pnpm dev` 只作为本地开发便利入口:确保后台 Host 可用,然后启动本地 WebUI,但不拥有 Host 生命周期。GUI / CUI 自动拉起的后台 Host 无 client、无 active work、无 active IM 时会按 15 分钟 idle timeout 自动退出;active IM 会保持 Host 存活。
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
@@ -102,7 +104,7 @@ docs/spec/ship/S####-slug.md
|
|
|
102
104
|
- 影响文件 / 包
|
|
103
105
|
- 风险与边界
|
|
104
106
|
|
|
105
|
-
没有 S spec
|
|
107
|
+
没有 S spec,不开始实现。局部 bug fix 可以不创建 S spec;如果修复会改变稳定契约、配置/协议/数据边界或用户可见产品方向,就先补 S spec。
|
|
106
108
|
|
|
107
109
|
### 3. Ship
|
|
108
110
|
|
|
@@ -140,7 +142,7 @@ S####: <type>: <description>
|
|
|
140
142
|
|
|
141
143
|
规则:
|
|
142
144
|
|
|
143
|
-
- 一个 PR 对应一个 S spec。
|
|
145
|
+
- 一个 PR 对应一个 S spec;局部 bug fix 可以不对应 S spec。
|
|
144
146
|
- Commit message 使用 title-only semantic commit:只写标题,不写正文。
|
|
145
147
|
- 按业务含义拆 commit,不把无关实现混在一起。
|
|
146
148
|
- 文档、实现、测试可以拆 commit,但 PR title 必须带 S 编号。
|
|
@@ -205,9 +207,12 @@ pnpm release patch --no-generate-notes
|
|
|
205
207
|
- 检查 working tree
|
|
206
208
|
- 执行 check
|
|
207
209
|
- 执行 WebUI production build
|
|
210
|
+
- 执行 GUI production build
|
|
208
211
|
- 构建 public `scorel` npm package
|
|
212
|
+
- 将同版本 public `scorel` CLI runtime vendored 进 GUI app bundle,供 packaged GUI 用 bundle 内绝对路径启动本机 Host
|
|
209
213
|
- 执行 `npm pack` 安装烟雾测试
|
|
210
214
|
- bump 所有 package version
|
|
215
|
+
- 构建 GUI macOS dmg / zip release assets,并生成 `latest-mac.yml` 与 blockmap 增量更新 metadata
|
|
211
216
|
- 默认用 DeepSeek V4 Flash 从上一个 `v*` tag 之后的 commits 生成 changelog notes
|
|
212
217
|
- 更新 changelog;只有显式 `--no-generate-notes` 时才写入最小版本标题
|
|
213
218
|
- commit `release: vX.Y.Z`
|
|
@@ -215,11 +220,11 @@ pnpm release patch --no-generate-notes
|
|
|
215
220
|
- publish root `scorel` package to npm
|
|
216
221
|
- push branch + tag
|
|
217
222
|
- create GitHub Release from the same generated changelog notes
|
|
218
|
-
- upload the same-version `npm pack` tarball
|
|
223
|
+
- upload the same-version `npm pack` tarball and GUI macOS release assets to the GitHub Release
|
|
219
224
|
|
|
220
225
|
Release notes 使用 `DEEPSEEK_API_KEY` 调用 DeepSeek 官方 API,默认 endpoint 为 `https://api.deepseek.com/v1`,默认模型为 `deepseek-v4-flash`。Dry-run 在缺少 key 或 API 失败时可打印 deterministic fallback preview;正式 release 默认要求 AI notes 成功,除非显式传入 `--no-generate-notes`。
|
|
221
226
|
|
|
222
|
-
GitHub Actions 提供手动触发入口,默认执行 `patch` dry-run。正式 release 使用 `GITHUB_TOKEN` 创建 GitHub Release;正式 publish 需要仓库 secret `NPM_TOKEN`,对应 npm 账号当前为 `chanlerdev`。AI release notes 需要仓库 secret `DEEPSEEK_API_KEY`。
|
|
227
|
+
GitHub Actions 提供手动触发入口,默认执行 `patch` dry-run。正式 release 使用 `GITHUB_TOKEN` 创建 GitHub Release;正式 publish 需要仓库 secret `NPM_TOKEN`,对应 npm 账号当前为 `chanlerdev`。AI release notes 需要仓库 secret `DEEPSEEK_API_KEY`。GUI macOS 产物当前以 unsigned build 发布,workflow 设置 `CSC_IDENTITY_AUTO_DISCOVERY=false`;有 Apple Developer 账号后再补 signing/notarization。
|
|
223
228
|
|
|
224
229
|
---
|
|
225
230
|
|
package/docs/spec/events.md
CHANGED
|
@@ -143,7 +143,22 @@ interface CompactEvent extends PersistentEventBase {
|
|
|
143
143
|
|
|
144
144
|
构建 context 时:从 leaf 往 root 走,遇到 CompactEvent → 注入 summary,停止继续向上。旧事件仍在 JSONL 中(可查阅),但不进入 LLM context。
|
|
145
145
|
|
|
146
|
-
### 4.5 `
|
|
146
|
+
### 4.5 `context_control` — 控制上下文投影
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
interface ContextControlEvent extends PersistentEventBase {
|
|
150
|
+
type: "context_control";
|
|
151
|
+
operation: "hide_user_turn";
|
|
152
|
+
anchorUserEventId: EventId;
|
|
153
|
+
throughEventId: EventId;
|
|
154
|
+
actor: "agent" | "user" | "system";
|
|
155
|
+
reason?: string;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`hide_user_turn` 隐藏一个已完成 user turn span:从 `anchorUserEventId` 开始,到同一路径下一条 `user_message` 前一条事件结束。它只影响未来 `buildContext()` 的 LLM 输入投影;原始 JSONL 事件仍保留并可用于 UI、审计和 resync。
|
|
160
|
+
|
|
161
|
+
### 4.6 `channel_inject` — 外部来源元数据
|
|
147
162
|
|
|
148
163
|
```typescript
|
|
149
164
|
interface ChannelInjectEvent extends PersistentEventBase {
|
|
@@ -340,6 +355,7 @@ type LlmAction =
|
|
|
340
355
|
| `rewind` | `skip` | "回退到此处" 标记 |
|
|
341
356
|
| `branch` | `skip` | "切换分支" 标记 |
|
|
342
357
|
| `compact` | `barrier` — 注入 summary,停止向上遍历 | "已压缩" 折叠块 |
|
|
358
|
+
| `context_control` | `filter` — 从未来 LLM context 中排除指定 user turn span | "已 snip" 标记 |
|
|
343
359
|
| `channel_inject` | `skip` | 来源 badge "from Telegram" |
|
|
344
360
|
| `session_info` | `skip` | "模型切换为 X" 通知 |
|
|
345
361
|
| `custom` | `skip` | Extension 自定义 |
|
package/docs/spec/session.md
CHANGED
|
@@ -345,6 +345,17 @@ if (estimateTokens(compactCandidates) > threshold) {
|
|
|
345
345
|
- 在 compact 点之前分叉的其他分支不受影响
|
|
346
346
|
- 旧事件仍在 JSONL 中,可供历史浏览
|
|
347
347
|
|
|
348
|
+
### 6.3 Snip Context Control
|
|
349
|
+
|
|
350
|
+
`snip` 不删除 JSONL。它 append `context_control operation="hide_user_turn"`,让后续 `buildContext()` 在 active path 上过滤一个已完成 user turn span。
|
|
351
|
+
|
|
352
|
+
安全边界:
|
|
353
|
+
|
|
354
|
+
- 目标必须是当前 active path 上的 `user_message`。
|
|
355
|
+
- 目标之后必须存在下一条 `user_message`,因此不能 snip 当前正在执行的 turn。
|
|
356
|
+
- 隐藏范围是目标 `user_message` 到下一条 `user_message` 前一条事件,保证 tool_call / tool_result 成对隐藏,不留下孤儿工具结果。
|
|
357
|
+
- 原始事件仍保留在 JSONL 中,UI 和审计可以继续查看。
|
|
358
|
+
|
|
348
359
|
---
|
|
349
360
|
|
|
350
361
|
## 7. 两层消息在本模块的落点
|
|
@@ -355,6 +366,7 @@ if (estimateTokens(compactCandidates) > threshold) {
|
|
|
355
366
|
- buildContext 通用遍历时调用每个 event 的 handler,不 hardcode 任何类型
|
|
356
367
|
- `rewind` / `branch` / `channel_inject` / `session_info` / `custom` → `skip`(不进入 LLM)
|
|
357
368
|
- `compact` → `barrier`(注入 summary,停止向上)
|
|
369
|
+
- `context_control` → `filter`(从未来 LLM context 排除指定 user turn span)
|
|
358
370
|
- `message`(meta.source = "steer")→ `merge_prev`(合入前一条 tool_result 的 `<system-reminder>`)
|
|
359
371
|
|
|
360
372
|
换言之,应用层能玩的花样很多,LLM 始终只看到 handler 声明要暴露的内容。
|
|
@@ -29,7 +29,7 @@ Lock M9 GUI as a Project-first desktop app before implementation. The GUI should
|
|
|
29
29
|
|
|
30
30
|
- Do not scaffold Electron in S0064.
|
|
31
31
|
- Do not implement GUI screens.
|
|
32
|
-
- Do not add SSH, direct WS + token, OAuth, account systems, or GUI auto-update.
|
|
32
|
+
- Do not add SSH, direct WS + token, OAuth, account systems, or GUI auto-update in S0064. GUI auto-update is introduced later by S0105 as release infrastructure.
|
|
33
33
|
- Do not publish or package desktop installers.
|
|
34
34
|
- Do not change the public npm CLI package surface.
|
|
35
35
|
|
|
@@ -76,10 +76,17 @@ Host runtime must use the selected model for each session/turn:
|
|
|
76
76
|
available model or role;
|
|
77
77
|
- CLI can continue using the default role without exposing a new command flag in this
|
|
78
78
|
spec;
|
|
79
|
-
- GUI composer can choose an available model for
|
|
79
|
+
- GUI composer can choose an available model for the next main chat prompt, including
|
|
80
|
+
prompts sent into an existing session;
|
|
81
|
+
- background model tasks such as session title generation, session memory, foreground
|
|
82
|
+
compact, and memory dream use the configured `auxiliary` role unless a later spec
|
|
83
|
+
defines a more specific routing contract;
|
|
80
84
|
- session metadata records the selected model id and role when known;
|
|
81
85
|
- session header persists enough selected-model metadata to keep resume auditable if
|
|
82
86
|
config later changes;
|
|
87
|
+
- if a restored session references a selected model that no longer exists in the
|
|
88
|
+
current device config, Host falls back through the persisted role or current
|
|
89
|
+
`standard` role instead of failing attach/resume;
|
|
83
90
|
- assistant events keep recording actual provider/model metadata from pi-ai.
|
|
84
91
|
|
|
85
92
|
Tool creation must use the actual selected model's context window, not a global model
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# S0103: Daemon Lifecycle And Settings Resilience
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Clarify daemon lifetime by entrypoint and make GUI Settings resilient when switching devices and sections, especially after selecting a Relay device.
|
|
6
|
+
|
|
7
|
+
Business value: a VPS demo host should stay online when the user explicitly starts it, while GUI/CUI convenience daemons still clean themselves up after local use. Settings failures must surface as recoverable errors, not a black renderer.
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
- `scorel host start` launches a background host that stays alive until explicit stop, process signal, crash, or machine shutdown.
|
|
12
|
+
- `scorel host serve` is foreground: it stays alive until Ctrl+C / SIGTERM unless the user explicitly provides `--idle-timeout-ms`.
|
|
13
|
+
- GUI auto-start and `scorel up` auto-start keep the existing 15 minute idle shutdown policy.
|
|
14
|
+
- GUI auto-start binds an ephemeral local port so a user-owned daemon on the default port cannot make GUI startup fail.
|
|
15
|
+
- `--idle-timeout-ms 0` remains the explicit "no idle shutdown" value.
|
|
16
|
+
- GUI Settings must ignore stale settings responses from a previously selected device.
|
|
17
|
+
- GUI Settings must render a local error fallback instead of blacking out the whole app when a Settings section throws.
|
|
18
|
+
- CDP verification covers Settings remote-device switching without renderer errors.
|
|
19
|
+
|
|
20
|
+
## Not In Scope
|
|
21
|
+
|
|
22
|
+
- Changing active IM keepalive semantics. Active IM still prevents idle shutdown.
|
|
23
|
+
- Adding a new public `--keep-alive` flag; this spec keeps the existing `--idle-timeout-ms 0` primitive and fixes defaults.
|
|
24
|
+
- Remote SSH device installation or management.
|
|
25
|
+
|
|
26
|
+
## Acceptance Criteria
|
|
27
|
+
|
|
28
|
+
- Direct `scorel host start` spawns `host serve` with idle shutdown disabled by default.
|
|
29
|
+
- Direct `scorel host serve` does not idle-exit by default; Ctrl+C/SIGTERM still stops it.
|
|
30
|
+
- `scorel up` spawns the daemon with a 15 minute idle timeout.
|
|
31
|
+
- GUI auto-start spawns the daemon with a 15 minute idle timeout.
|
|
32
|
+
- GUI auto-start uses the persisted `daemon.json` actual port instead of assuming the default daemon port is free.
|
|
33
|
+
- Settings device changes reset device-scoped settings state and ignore stale async responses.
|
|
34
|
+
- Settings section render errors show an in-app fallback and do not remove the app shell.
|
|
35
|
+
- CDP GUI verification seeds a device config, switches to a remote device in Settings, flips across Settings sections, and fails on renderer errors.
|
|
36
|
+
|
|
37
|
+
## Tests
|
|
38
|
+
|
|
39
|
+
- CLI daemon tests cover background start idle disable, foreground serve default no-idle, explicit idle timeout, and active IM keepalive.
|
|
40
|
+
- `scorel up` tests assert the internal daemon spawn passes the 15 minute idle timeout.
|
|
41
|
+
- GUI renderer tests cover stale local settings data not overwriting remote settings data.
|
|
42
|
+
- CDP GUI verification covers remote Settings section switching and device-level config persistence.
|
|
43
|
+
|
|
44
|
+
## Files
|
|
45
|
+
|
|
46
|
+
- `apps/cli/src/daemon-cli.ts`
|
|
47
|
+
- `apps/cli/src/up-cli.ts`
|
|
48
|
+
- `apps/gui/src/main.ts`
|
|
49
|
+
- `apps/gui/src/renderer/App.tsx`
|
|
50
|
+
- `apps/gui/src/renderer/settings/SettingsShell.tsx`
|
|
51
|
+
- `apps/gui/src/renderer/settings/sections/ModelSection.tsx`
|
|
52
|
+
- `apps/gui/src/renderer/settings/sections/ProviderSection.tsx`
|
|
53
|
+
- `scripts/verify-m9-gui-cdp-e2e.ts`
|
|
54
|
+
- `docs/SHIP.md`
|
|
55
|
+
- `docs/ROADMAP.md`
|
|
56
|
+
- `docs/CHANGELOG.md`
|
|
57
|
+
|
|
58
|
+
## Risks
|
|
59
|
+
|
|
60
|
+
- A foreground host without idle shutdown can run forever. That is intended because terminal ownership and Ctrl+C are visible to the user.
|
|
61
|
+
- GUI/CUI auto-start must remain explicit about its 15 minute idle timeout; otherwise changing host defaults would make local helper daemons permanent.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# S0104: Tool Result Artifacts
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Keep long tool results useful without letting them dominate model context.
|
|
6
|
+
|
|
7
|
+
When a tool result is too large, Scorel should preserve the full result as a session-owned artifact and put only a compact, actionable projection in the model-facing tool result.
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
- Add a session-owned artifact path for oversized tool results:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
~/.scorel/sessions/{sessionId}.artifacts/{toolCallId}/result.txt
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Start with `Bash` stdout/stderr because it is the highest-risk long-output source.
|
|
18
|
+
- Preserve the full command result in `result.txt`, including exit code, cwd, stdout, and stderr.
|
|
19
|
+
- Return a compact tool result containing:
|
|
20
|
+
- exit code;
|
|
21
|
+
- cwd;
|
|
22
|
+
- full artifact path;
|
|
23
|
+
- complete result byte count;
|
|
24
|
+
- stdout/stderr byte counts;
|
|
25
|
+
- a budgeted head/tail projection of the oversized streams.
|
|
26
|
+
- Treat `maxOutputBytes` as the total projection snippet budget across stdout/stderr, not as a per-stream head/tail allowance. For example, a 16,000-byte projection budget should not turn into 16,000 bytes of stdout head plus 16,000 bytes of stdout tail plus the same again for stderr.
|
|
27
|
+
- Keep session JSONL append-only. Do not rewrite or delete old tool result events.
|
|
28
|
+
- Keep diagnostics free of full prompt text and full tool results.
|
|
29
|
+
- Keep Relay and attach-cache out of this storage path.
|
|
30
|
+
|
|
31
|
+
## Not In Scope
|
|
32
|
+
|
|
33
|
+
- Background Bash, task id, poll, stop, or monitor semantics.
|
|
34
|
+
- Artifact retention policy, compression, upload, or remote retrieval.
|
|
35
|
+
- Rewriting existing session JSONL files.
|
|
36
|
+
- Applying artifact projection to `Read`, `Grep`, `Glob`, or MCP tools.
|
|
37
|
+
- Provider-specific token accounting.
|
|
38
|
+
|
|
39
|
+
## Acceptance Criteria
|
|
40
|
+
|
|
41
|
+
- `Bash` output at or below the existing output limit behaves as before.
|
|
42
|
+
- `Bash` output above the limit writes the complete result to `result.txt`.
|
|
43
|
+
- Oversized `Bash` model-facing content includes the artifact path, `resultBytes`, and budgeted head/tail snippets instead of only the leading bytes.
|
|
44
|
+
- The artifact file contains the complete stdout/stderr text, not only the projected snippets.
|
|
45
|
+
- The tool result details expose artifact metadata for UI/diagnostics without requiring it to enter rebuilt model context.
|
|
46
|
+
- Existing `buildContext()` behavior still strips tool execution details from replayed model context.
|
|
47
|
+
- `pnpm --filter @scorel/core test -- src/tools/coding-tools.test.ts`
|
|
48
|
+
- `pnpm --filter @scorel/daemon test -- src/embedded/embedded.test.ts`
|
|
49
|
+
- `pnpm typecheck && pnpm test`
|
|
50
|
+
|
|
51
|
+
## Impacted Files
|
|
52
|
+
|
|
53
|
+
- `packages/core/src/tools/coding-tools.ts`
|
|
54
|
+
- `packages/core/src/tools/coding-tools.test.ts`
|
|
55
|
+
- `packages/core/src/session/index.ts`
|
|
56
|
+
- `packages/daemon/src/index.ts`
|
|
57
|
+
- CLI / GUI runtime creation paths that call `createRealRuntime`
|
|
58
|
+
- `docs/ROADMAP.md`
|
|
59
|
+
|
|
60
|
+
## Risks And Boundaries
|
|
61
|
+
|
|
62
|
+
- Full command output can contain secrets. The artifact path is local session data and must not be copied into diagnostics, attach-cache, or Relay.
|
|
63
|
+
- Head/tail snippets can still expose sensitive text. This is no worse than the current truncated result, but future permission policy should handle sensitive commands explicitly.
|
|
64
|
+
- Artifact paths are local to the daemon-owning machine. Remote clients can see the path as evidence, but remote file retrieval is a separate future protocol.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# S0105: CLI Update And GUI Release
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Make Scorel's user-facing command surface complete enough for release users, and make CLI / GUI updates part of the same release story.
|
|
6
|
+
|
|
7
|
+
## Scope
|
|
8
|
+
|
|
9
|
+
- Add top-level `scorel version` / `scorel --version`.
|
|
10
|
+
- Add manual `scorel update` and `scorel upgrade` commands for the public npm package.
|
|
11
|
+
- Add Host-side automatic npm update checks:
|
|
12
|
+
- check npm latest once per hour
|
|
13
|
+
- install only when no active work is running, or active work has been stale for at least three hours
|
|
14
|
+
- after a successful background update, stop the Host with an `auto-update` reason so the next entry start uses the new binary
|
|
15
|
+
- Keep `scorel` as the default interactive project command, and keep lifecycle/diagnostic commands grouped under product nouns: `host`, `pair`, `relay`, `webui`, `up`, `project`, `logs`.
|
|
16
|
+
- Add GUI release packaging to the same GitHub Release:
|
|
17
|
+
- Electron macOS dmg + zip targets
|
|
18
|
+
- `latest-mac.yml`
|
|
19
|
+
- `.blockmap` metadata for incremental updates
|
|
20
|
+
- `electron-updater` bootstrap in packaged GUI builds
|
|
21
|
+
- Add normal desktop update affordances:
|
|
22
|
+
- application menu `Check for Updates...`
|
|
23
|
+
- macOS status bar menu with show, settings, check updates, Host status, and quit
|
|
24
|
+
- Document unsigned macOS build handling for users without an Apple Developer account.
|
|
25
|
+
|
|
26
|
+
## Non-Goals
|
|
27
|
+
|
|
28
|
+
- Do not add auth/account commands before Scorel has a real account system.
|
|
29
|
+
- Do not add deprecated aliases for old command shapes.
|
|
30
|
+
- Do not publish GUI through npm.
|
|
31
|
+
- Do not claim notarization or Gatekeeper trust without Apple Developer signing credentials.
|
|
32
|
+
- Do not make Relay or hosted WebUI own update state.
|
|
33
|
+
|
|
34
|
+
## Contract
|
|
35
|
+
|
|
36
|
+
### CLI Surface
|
|
37
|
+
|
|
38
|
+
The stable user command groups are:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
scorel [--session <id>] [--cwd <dir>]
|
|
42
|
+
scorel chat [--session <id>] [--cwd <dir>]
|
|
43
|
+
scorel attach --session <id> --remote <ws-url> --token <token>
|
|
44
|
+
scorel host start|serve|status|stop|reset
|
|
45
|
+
scorel pair <pair-code>
|
|
46
|
+
scorel relay serve
|
|
47
|
+
scorel webui
|
|
48
|
+
scorel up
|
|
49
|
+
scorel project list|add|remove
|
|
50
|
+
scorel logs
|
|
51
|
+
scorel version
|
|
52
|
+
scorel update
|
|
53
|
+
scorel upgrade
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This mirrors the broad shape used by mature agent CLIs: one default interactive command, explicit session/control commands, and a direct update command.
|
|
57
|
+
|
|
58
|
+
### CLI Update
|
|
59
|
+
|
|
60
|
+
`scorel update` and `scorel upgrade` both:
|
|
61
|
+
|
|
62
|
+
- query `npm view @chanlerdev/scorel version`
|
|
63
|
+
- compare against the installed package version with semver ordering
|
|
64
|
+
- run `npm install -g @chanlerdev/scorel@<latest>` only when latest is newer
|
|
65
|
+
- print a clear no-op message when already current
|
|
66
|
+
|
|
67
|
+
Host auto-update uses the same updater helper. The active-work gate is generic: it reads Host runtime/queue activity, not filenames, paths, screenshots, or one failure sample.
|
|
68
|
+
|
|
69
|
+
### GUI Release
|
|
70
|
+
|
|
71
|
+
`apps/gui` remains private and separate from the npm CLI package. Release packaging uses Electron Builder with GitHub provider metadata so `electron-updater` can check the same GitHub Release.
|
|
72
|
+
|
|
73
|
+
The release asset set is:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
<npm pack tarball>
|
|
77
|
+
apps/gui/release/latest-mac.yml
|
|
78
|
+
apps/gui/release/*.dmg
|
|
79
|
+
apps/gui/release/*.dmg.blockmap
|
|
80
|
+
apps/gui/release/*.zip
|
|
81
|
+
apps/gui/release/*.zip.blockmap
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The macOS Action runs with `CSC_IDENTITY_AUTO_DISCOVERY=false` until signing/notarization credentials exist.
|
|
85
|
+
|
|
86
|
+
## Acceptance Criteria
|
|
87
|
+
|
|
88
|
+
- `scorel --help` lists update/version commands.
|
|
89
|
+
- `scorel --version` and `scorel version` print the installed version.
|
|
90
|
+
- `scorel update` / `scorel upgrade` have tested npm check/install behavior.
|
|
91
|
+
- Host auto-update gate is covered by tests.
|
|
92
|
+
- GUI packaged app initializes `electron-updater` only when packaged.
|
|
93
|
+
- GUI exposes manual update checks from both the application menu and the macOS status bar menu.
|
|
94
|
+
- GUI registers a macOS status bar menu with Host status and common app actions.
|
|
95
|
+
- Release script version lockstep includes `apps/gui/package.json`.
|
|
96
|
+
- Release script uploads GUI installer/update metadata assets to GitHub Release.
|
|
97
|
+
- README documents manual update, automatic update, GUI packaging, and unsigned macOS `xattr` workaround.
|
|
98
|
+
|
|
99
|
+
## Test Requirements
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pnpm --filter @scorel/app-cli test -- update-cli.test.ts
|
|
103
|
+
pnpm --filter @scorel/app-gui test -- main-menu.test.ts
|
|
104
|
+
node --test scripts/release-gui.test.mjs
|
|
105
|
+
pnpm typecheck
|
|
106
|
+
pnpm test
|
|
107
|
+
git diff --check
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Affected Paths
|
|
111
|
+
|
|
112
|
+
- `apps/cli/src/index.ts`
|
|
113
|
+
- `apps/cli/src/update-cli.ts`
|
|
114
|
+
- `apps/cli/src/daemon-cli.ts`
|
|
115
|
+
- `packages/daemon/src/index.ts`
|
|
116
|
+
- `apps/gui/package.json`
|
|
117
|
+
- `apps/gui/src/main.ts`
|
|
118
|
+
- `scripts/release.mjs`
|
|
119
|
+
- `.github/workflows/release.yml`
|
|
120
|
+
- `README.md`
|
|
121
|
+
- `docs/SHIP.md`
|
|
122
|
+
- `docs/ROADMAP.md`
|
|
123
|
+
|
|
124
|
+
## Risks
|
|
125
|
+
|
|
126
|
+
- `npm install -g` can fail on machines where the user lacks permission for the global prefix. The command reports the npm error instead of silently mutating local state.
|
|
127
|
+
- Auto-updating a running Host cannot replace the current Node process in-place. The short-stop mechanism exits after successful installation; GUI/WebUI/CLI entrypoints can then start the new binary.
|
|
128
|
+
- Unsigned macOS apps are viable for local distribution but not trustworthy public distribution. Notarization should be added once an Apple Developer account is available.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# S0106: Snip Context Control
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Let long-running sessions remove a completed user turn from future model context without deleting the underlying session record.
|
|
6
|
+
|
|
7
|
+
The business value is context hygiene: when an earlier user turn led the agent down a noisy or obsolete path, the user or agent can mark that whole turn as no longer relevant so future model calls stop paying attention to it. The original JSONL remains the evidence chain for UI, audit, resync, and debugging.
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
### Stable User Turn References
|
|
12
|
+
|
|
13
|
+
Every persisted `user_message` already has a durable `EventId`. S0106 treats that event id as the source of truth for snip targeting. The model-facing id is a stable short alias derived from the real `EventId`; the alias resolves back to the real event id but is not a storage key.
|
|
14
|
+
|
|
15
|
+
When the Host creates a `user_message`, it appends a model-only text block to that same persisted message:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
<system-reminder>
|
|
19
|
+
snip.userMessageId: u_...
|
|
20
|
+
</system-reminder>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The block is persisted with the message so future `buildContext()` replays do not rewrite earlier user messages and do not invalidate prompt-cache prefixes. UI projectors hide model-only text blocks from the visible transcript.
|
|
24
|
+
|
|
25
|
+
### Context Control Event
|
|
26
|
+
|
|
27
|
+
Add a persistent control event:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
type ContextControlEvent = {
|
|
31
|
+
type: "context_control";
|
|
32
|
+
operation: "hide_user_turn";
|
|
33
|
+
anchorUserEventId: EventId;
|
|
34
|
+
throughEventId: EventId;
|
|
35
|
+
actor: "agent" | "user" | "system";
|
|
36
|
+
reason?: string;
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The event is append-only and does not participate in the conversation tree. `buildContext()` folds these events as control state and filters the active path before producing LLM messages.
|
|
41
|
+
|
|
42
|
+
`hide_user_turn` semantics:
|
|
43
|
+
|
|
44
|
+
- `anchorUserEventId` must identify a `user_message` on the active session path.
|
|
45
|
+
- The hidden span starts at that user event.
|
|
46
|
+
- The hidden span ends at the event before the next `user_message` on the same path, or the active leaf when there is no later user message.
|
|
47
|
+
- The resolved end is stored as `throughEventId`.
|
|
48
|
+
- The span is hidden from future `buildContext()` calls after the control event is appended.
|
|
49
|
+
- Original events stay in JSONL and continue to be visible through session replay and UI projection.
|
|
50
|
+
|
|
51
|
+
### `snip` Tool
|
|
52
|
+
|
|
53
|
+
Expose a lazily available `Snip` runtime tool that lets the agent request hiding a completed user turn from future context. The tool accepts:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{ "userMessageId": "u_...", "reason": "optional short reason" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The Host validates the request, resolves the model-visible short alias to a target span, appends a `context_control` event, and returns a tool result describing what changed. The tool result is still part of the current turn; the hidden span disappears on the next context build.
|
|
60
|
+
|
|
61
|
+
The tool is session-context control, not a generic coding tool. It must be registered by the Host with access to the current lane, not by `createCodingTools()`.
|
|
62
|
+
|
|
63
|
+
Tool parameter schemas are owned by `AgentTool` definitions. Provider adapters must pass through the tool's declared schema instead of hard-coding behavior for specific tool names such as `snip`.
|
|
64
|
+
|
|
65
|
+
## Not In Scope
|
|
66
|
+
|
|
67
|
+
- Physically deleting, truncating, or rewriting historical JSONL.
|
|
68
|
+
- Arbitrary single-message deletion.
|
|
69
|
+
- Snipping across branches.
|
|
70
|
+
- User-facing GUI controls for browsing snipped spans.
|
|
71
|
+
- A CLI slash command.
|
|
72
|
+
- Automatic snip heuristics.
|
|
73
|
+
- Reusing `compact` for snip. Compact summarizes old context; snip excludes a specific user turn.
|
|
74
|
+
|
|
75
|
+
## Acceptance Criteria
|
|
76
|
+
|
|
77
|
+
- `PersistentEvent` includes `context_control`.
|
|
78
|
+
- Session replay folds `hide_user_turn` events into control state.
|
|
79
|
+
- `buildContext()` excludes the hidden user-turn span from future LLM context.
|
|
80
|
+
- The excluded span can include assistant tool calls and tool results without leaving orphan tool results in context.
|
|
81
|
+
- JSONL remains append-only; original user/assistant/tool events remain loadable after snip.
|
|
82
|
+
- Repeated snip of the same target is idempotent enough to keep context stable.
|
|
83
|
+
- Invalid targets fail as tool errors and do not append control events.
|
|
84
|
+
- `snip` is registered by the Host and can append `context_control` from a real runtime tool call path.
|
|
85
|
+
- The model can discover snippable user turn ids from its normal context projection; tests must not rely on out-of-band `send_message` response data.
|
|
86
|
+
- User turn ids are persisted at user-message creation time, so replaying the same turn in later provider calls does not change that message and preserves prompt-cache stability.
|
|
87
|
+
- Model-only short id blocks are hidden from WebUI and GUI transcript projection.
|
|
88
|
+
- The `snip` `AgentTool` schema exposes `userMessageId` and optional `reason`, and provider adapters preserve tool-owned schemas without name-specific branches.
|
|
89
|
+
- Full validation passes with `pnpm typecheck && pnpm test`.
|
|
90
|
+
|
|
91
|
+
## Testing Requirements
|
|
92
|
+
|
|
93
|
+
- Core session tests for context-control parsing, replay, and context filtering.
|
|
94
|
+
- Protocol tests for exhaustive event handling.
|
|
95
|
+
- Daemon embedded test proving `snip` appends `context_control` and the next provider call no longer receives the hidden turn.
|
|
96
|
+
|
|
97
|
+
## Impacted Files
|
|
98
|
+
|
|
99
|
+
- `packages/protocol/src/events.ts`
|
|
100
|
+
- `packages/protocol/src/index.test.ts`
|
|
101
|
+
- `packages/core/src/session/index.ts`
|
|
102
|
+
- `packages/core/src/session/session.test.ts`
|
|
103
|
+
- `packages/core/src/tools/index.ts`
|
|
104
|
+
- `packages/daemon/src/index.ts`
|
|
105
|
+
- `packages/daemon/src/embedded/embedded.test.ts`
|
|
106
|
+
- `docs/ROADMAP.md`
|
|
107
|
+
- `README.md`
|
|
108
|
+
|
|
109
|
+
## Risks And Boundaries
|
|
110
|
+
|
|
111
|
+
- Hiding the wrong turn is worse than compacting too much. Target resolution must use real `EventId`s and reject non-user targets.
|
|
112
|
+
- Tool-call/tool-result pairing can be broken by arbitrary deletion. This spec only hides full user-turn spans.
|
|
113
|
+
- Snip is context projection, not evidence deletion. UI and session replay must still show the original events unless a later explicit product decision adds a separate display filter.
|