@logicseek/hello-cc 1.0.5 → 1.1.0-rc.3
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/CHANGELOG.md +72 -0
- package/docs/codex-account.zh-CN.md +38 -0
- package/docs/codex-protocol.md +59 -0
- package/docs/commands.md +9 -0
- package/docs/commands.zh-CN.md +7 -0
- package/docs/macos-process-identity.md +2 -0
- package/docs/native.md +179 -14
- package/docs/native.zh-CN.md +136 -6
- package/docs/web-handoff.zh-CN.md +118 -8
- package/lib/cli/app.mjs +47 -4
- package/lib/cli/commands/coordination.mjs +14 -4
- package/lib/cli/commands/dsh.mjs +1 -1
- package/lib/cli/commands/gc.mjs +22 -15
- package/lib/cli/commands/hook.mjs +19 -3
- package/lib/cli/commands/install.mjs +80 -10
- package/lib/cli/commands/misc.mjs +36 -9
- package/lib/cli/commands/native.mjs +4 -38
- package/lib/cli/commands/peer.mjs +3 -0
- package/lib/cli/commands/run.mjs +13 -6
- package/lib/cli/commands/tmux.mjs +1 -2
- package/lib/cli-runtime.mjs +19 -2
- package/lib/core/coordination/results.mjs +27 -10
- package/lib/core/sessions/hook-root-identity.mjs +47 -0
- package/lib/core/sessions/launch.mjs +7 -1
- package/lib/db/connection.mjs +140 -42
- package/lib/db/schema.mjs +59 -0
- package/lib/diagnostics/codex-protocol.mjs +105 -0
- package/lib/guidance.mjs +21 -36
- package/lib/integrations/codex-account.mjs +143 -0
- package/lib/integrations/codex-interactions.mjs +13 -11
- package/lib/integrations/dsh-collaboration.mjs +6 -12
- package/lib/integrations/dsh-cordis.mjs +17 -13
- package/lib/integrations/dsh.mjs +16 -11
- package/lib/integrations/mcp-elicitation.mjs +116 -0
- package/lib/integrations/mcp-url-elicitation.mjs +25 -0
- package/lib/integrations/native/claude.mjs +24 -6
- package/lib/integrations/native/codex.mjs +38 -7
- package/lib/integrations/native/dsh-acp.mjs +67 -24
- package/lib/integrations/native/index.mjs +4 -1
- package/lib/integrations/native/interactions.mjs +2 -1
- package/lib/integrations/native/jsonrpc.mjs +37 -5
- package/lib/integrations/native/telemetry.mjs +30 -0
- package/lib/process/identity.mjs +4 -0
- package/lib/process/pinned-cwd.mjs +302 -0
- package/lib/process/pinned-guidance.mjs +138 -0
- package/lib/process/pinned-project-state.mjs +105 -0
- package/lib/process/selected-cwd-identity.mjs +95 -0
- package/lib/runtime/buffer-evidence.mjs +2 -1
- package/lib/runtime/client.mjs +9 -0
- package/lib/runtime/native/client.mjs +4 -1
- package/lib/runtime/native/history.mjs +140 -0
- package/lib/runtime/native/launcher.mjs +106 -0
- package/lib/runtime/native/service.mjs +64 -8
- package/lib/runtime/native/store.mjs +83 -58
- package/lib/runtime/paths.mjs +17 -2
- package/lib/runtime/private-file.mjs +76 -0
- package/lib/runtime/private-state.mjs +546 -0
- package/lib/runtime/project-context.mjs +2 -1
- package/lib/runtime/project-path.mjs +92 -20
- package/lib/runtime/project-trust.mjs +79 -0
- package/lib/runtime/projects.mjs +9 -3
- package/lib/runtime/state-migration.mjs +697 -0
- package/lib/runtime/state.mjs +69 -27
- package/lib/shared/automatic-result-key.mjs +6 -0
- package/lib/shared/json-file.mjs +55 -6
- package/lib/shared/redact.mjs +2 -1
- package/lib/ui/help.mjs +6 -4
- package/lib/web/agent-defaults.mjs +110 -0
- package/lib/web/auto-attach.mjs +3 -2
- package/lib/web/browser/contracts.d.ts +10 -0
- package/lib/web/browser/core.mjs +1997 -0
- package/lib/web/browser/project-data.mjs +158 -0
- package/lib/web/browser/session-sync.mjs +82 -0
- package/lib/web/browser-assets.mjs +19 -0
- package/lib/web/buffer-gc-runtime.mjs +2 -2
- package/lib/web/codex-app-server.mjs +111 -37
- package/lib/web/codex-sessions.mjs +61 -12
- package/lib/web/context-files.mjs +82 -0
- package/lib/web/cookie-auth.mjs +51 -3
- package/lib/web/external-sessions.mjs +76 -9
- package/lib/web/http-routes.mjs +238 -25
- package/lib/web/http.mjs +50 -4
- package/lib/web/liveness-reaper.mjs +2 -2
- package/lib/web/native-sessions.mjs +323 -14
- package/lib/web/project-contexts.mjs +236 -44
- package/lib/web/project-file-write.mjs +249 -0
- package/lib/web/project-files.mjs +268 -0
- package/lib/web/pty-sessions.mjs +11 -3
- package/lib/web/runtime-main.mjs +132 -80
- package/lib/web/session-serialize.mjs +87 -8
- package/lib/web/session-state-sync.mjs +98 -0
- package/lib/web/shutdown-diagnostics.mjs +38 -0
- package/lib/web/shutdown-response.mjs +21 -0
- package/lib/web/shutdown-state.mjs +91 -0
- package/lib/web/startup.mjs +103 -35
- package/lib/web/task-results.mjs +19 -19
- package/lib/web/tls.mjs +84 -33
- package/lib/web/tmux-sessions.mjs +73 -9
- package/lib/web/tmux-stream.mjs +36 -8
- package/lib/web/ui-agent-defaults.mjs +149 -0
- package/lib/web/ui-agent-start.mjs +330 -0
- package/lib/web/ui-codex-account.mjs +81 -0
- package/lib/web/ui-codex.mjs +105 -85
- package/lib/web/ui-command-palette.mjs +21 -5
- package/lib/web/ui-file-writes.mjs +220 -0
- package/lib/web/ui-files.mjs +231 -0
- package/lib/web/ui-handoff.mjs +10 -2
- package/lib/web/ui-history.mjs +175 -105
- package/lib/web/ui-i18n.mjs +280 -8
- package/lib/web/ui-interactions.mjs +107 -6
- package/lib/web/ui-native-timeline.mjs +326 -0
- package/lib/web/ui-native.mjs +93 -43
- package/lib/web/ui-review.mjs +5 -3
- package/lib/web/ui-safe-markdown.mjs +79 -0
- package/lib/web/ui-session-tools.mjs +224 -0
- package/lib/web/ui-template.mjs +29 -1968
- package/lib/web/ui-terminal-find.mjs +5 -3
- package/lib/web/ui-workbench.mjs +5 -3
- package/lib/web/ui-workspace.mjs +3 -0
- package/package.json +8 -2
- package/scripts/benchmark-session-sync.mjs +53 -0
- package/scripts/codex-protocol.mjs +88 -0
- package/scripts/dsh-approval-layers-acceptance.mjs +172 -0
- package/scripts/dsh-package-provenance.mjs +118 -0
- package/scripts/mcp-form-live-fixture.mjs +81 -0
- package/scripts/native-bounded-live-acceptance.mjs +193 -0
- package/scripts/native-fixture-root.mjs +49 -0
- package/scripts/native-installed-acceptance.mjs +611 -0
- package/scripts/native-stability-checks.mjs +40 -0
- package/scripts/regression-cookie-expiry.mjs +70 -0
- package/scripts/regression-http-transport.mjs +9 -0
- package/scripts/regression-terminal-marker.mjs +95 -0
- package/scripts/regression.mjs +481 -219
- package/scripts/shim-reentry-probe.mjs +105 -0
- package/scripts/web-acceptance-diagnostics.mjs +90 -0
- package/scripts/web-codex-account-acceptance.mjs +178 -0
- package/scripts/web-file-preview-checks.mjs +302 -0
- package/scripts/web-mcp-form-acceptance.mjs +134 -0
- package/scripts/web-mcp-form-live-acceptance.mjs +368 -0
- package/scripts/web-native-handoff-checks.mjs +128 -0
- package/scripts/web-native-interaction-acceptance.mjs +219 -18
- package/scripts/web-native-interaction-diagnostics.mjs +80 -0
- package/scripts/web-native-model-acceptance.mjs +22 -7
- package/scripts/web-session-tools-checks.mjs +112 -0
- package/scripts/web-workbench-acceptance.mjs +435 -0
- package/scripts/web-workbench-installed-acceptance.mjs +122 -0
package/docs/native.zh-CN.md
CHANGED
|
@@ -48,6 +48,38 @@ npm install --no-save --package-lock=false @anthropic-ai/claude-agent-sdk@0.3.28
|
|
|
48
48
|
已有独立回执 (源码目录: `docs/verification/2026-10-02-native-web-claude-default-sdk.json`),不代表
|
|
49
49
|
发布包或员工设备已完成安装验收。
|
|
50
50
|
|
|
51
|
+
## 从 Web 新建
|
|
52
|
+
|
|
53
|
+
运行 `hcc web`,选择项目,再点击“新建 Agent”。Codex、Claude 和 DeepSeek Harness
|
|
54
|
+
默认使用“后台 Agent”,创建 native worker 并按需启动或复用该项目的独立 native
|
|
55
|
+
runtime。无需先运行 `hcc native start`;上述 provider 安装和认证要求仍然适用。
|
|
56
|
+
|
|
57
|
+
顶部“设置”可保存项目默认 provider,以及各 provider 的默认模型和项目内工作目录。
|
|
58
|
+
新建表单会预填这些值;未设置工作目录时使用项目根目录。worker 继续共享所选项目的
|
|
59
|
+
HCC 任务和消息总线。要在根目录之外工作,先选择或添加相应项目。“模型(可选)”
|
|
60
|
+
留空时使用 provider 当前配置,填写时需使用该 provider 支持的模型值;“名称(可选)”
|
|
61
|
+
留空时自动生成 peer 名称。
|
|
62
|
+
|
|
63
|
+
这些默认值只用于后续 Web 新建 native worker,不改变既有 worker、恢复或 CLI 启动。
|
|
64
|
+
配置由项目数据库保存,跨浏览器读取;并发保存发生冲突时需重新载入核对。详情见
|
|
65
|
+
[项目启动默认值](web-handoff.zh-CN.md#项目-agent-启动默认值)。
|
|
66
|
+
|
|
67
|
+
“新建 Agent”创建新 native 会话;项目栏“历史”中的“HCC 保留历史”可查看已保存的
|
|
68
|
+
worker,并显式恢复已关闭的 worker。恢复保留原 peer 和 provider 会话 ID,重新核对
|
|
69
|
+
所有权后启动新执行器。CLI resume 继续可用。“高级选项”保留终端 CLI、Codex App
|
|
70
|
+
Server 及各自原有的历史恢复操作。Shell 使用终端,DeepSeek Harness 使用后台 worker。
|
|
71
|
+
|
|
72
|
+
创建后在同一 Web 会话内发送提示、查看投递回执或处理审批。创建 worker 不代表模型
|
|
73
|
+
任务已经完成。关闭页面或停止 Web 都保留独立 native runtime 和 worker;不再需要时
|
|
74
|
+
明确关闭 worker。下方带日期的既有验收记录不代表这个新建入口已通过真实模型或发布
|
|
75
|
+
验收。详细操作见 [Web 指南](web-handoff.zh-CN.md)。
|
|
76
|
+
|
|
77
|
+
顶部“文件”可浏览项目文件与生成产物,也可显式上传新文件(最大 10 MiB)或编辑完整
|
|
78
|
+
UTF-8 文本(最大 1 MiB),无需创建 worker。同名上传不覆盖,文本保存会检查版本;
|
|
79
|
+
冲突或回执不确定时保留草稿。这些操作不会把文件发送给模型。详情见
|
|
80
|
+
[文件与产物预览](web-handoff.zh-CN.md#浏览文件与产物)及
|
|
81
|
+
[上传与编辑](web-handoff.zh-CN.md#上传与编辑项目文件)。
|
|
82
|
+
|
|
51
83
|
## CLI 使用
|
|
52
84
|
|
|
53
85
|
在需要共享状态的项目目录中运行,或使用已有全局 `--root`、`--db` 指定项目和数据库。
|
|
@@ -80,7 +112,7 @@ hcc msg inbox --peer coordinator
|
|
|
80
112
|
| `hcc native deliveries` | 可选 `--peer NAME`,查看投递回执 |
|
|
81
113
|
| `hcc native events` | 必须 `--peer NAME`;可选 `--after ID`,查看有界事件历史 |
|
|
82
114
|
| `hcc native requests` | 必须 `--peer NAME`;查看与该执行器、会话、turn 绑定的待处理请求 |
|
|
83
|
-
| `hcc native respond` | 必须 `--peer NAME --request ID --decision accept\|decline\|cancel
|
|
115
|
+
| `hcc native respond` | 必须 `--peer NAME --request ID --decision accept\|decline\|cancel`;权限子集、问题答案或 MCP 表单内容通过 `--response-file JSON` 提交 |
|
|
84
116
|
| `hcc native interrupt` | 必须 `--peer NAME`;可选 `--turn ID`,请求中断活动 turn |
|
|
85
117
|
| `hcc native close` | 必须 `--peer NAME`,关闭该 worker 持有的连接或进程 |
|
|
86
118
|
| `hcc native down` | 请求关闭 worker 和停止 runtime,返回停止请求回执 |
|
|
@@ -135,6 +167,11 @@ hcc native start --peer codex-reviewer --provider codex --resume last
|
|
|
135
167
|
的连接恢复会话历史,不是附着已有的活动 TUI 或桌面实例。HCC 无法证明外部应用
|
|
136
168
|
没有独立打开同一个保存会话,因此不要同时在 owned runtime 外写入该会话。
|
|
137
169
|
|
|
170
|
+
新保存的 worker 还记录工作目录的文件系统身份;即使路径文字未变,恢复前也必须
|
|
171
|
+
重新匹配该身份。缺少此证据的旧 worker 仍可在 HCC 历史中读取,但不能自动恢复;
|
|
172
|
+
人工核验与关联流程尚未实现。Web 历史会先标为不可恢复,native 服务在实际接纳时
|
|
173
|
+
再次校验。
|
|
174
|
+
|
|
138
175
|
worker 获得明确的 `HCC_ROOT`、`HCC_DB`、`HCC_PEER`、`HCC_NATIVE_OWNER`。provider hook
|
|
139
176
|
必须匹配该 peer 的 native transport owner。native hook 路径只刷新 owner 心跳和续
|
|
140
177
|
期其锁,不覆盖 provider binding 或进程身份、不再次注入 inbox、不 ACK 消息,也
|
|
@@ -147,12 +184,16 @@ ID。观察窗口不能应答,控制权切换后旧窗口的 epoch 失效。
|
|
|
147
184
|
|
|
148
185
|
| Provider | 已接入的人工交互 |
|
|
149
186
|
| --- | --- |
|
|
150
|
-
| Codex | 命令/文件审批、所请求文件与网络权限的子集、明确的 turn/session 有效期、选项/自由输入/敏感问题,以及单次空表单 MCP
|
|
187
|
+
| Codex | 命令/文件审批、所请求文件与网络权限的子集、明确的 turn/session 有效期、选项/自由输入/敏感问题,以及单次空表单 MCP 工具确认与常用 MCP 表单字段 |
|
|
151
188
|
| Claude | SDK 工具权限 callback,批准原始输入本次执行,不改写工具参数 |
|
|
152
189
|
| dsh ACP | 选择 provider 提供的 `allow_once`,不自动选择 `allow_always` |
|
|
153
190
|
|
|
154
191
|
rc.2 的 ACP 审批可能只携带工具 ID。适配器会关联同一 session/turn 的工具更新以展示操作输入;等待后仍缺输入或输入被截断时可以拒绝,允许会返回 `NATIVE_APPROVAL_CONTEXT_MISSING`。实际安装与拒绝证明见 dsh 验收 (源码目录: `docs/verification/2026-10-02-dsh-cordis-native.md`)。
|
|
155
192
|
|
|
193
|
+
Native 审批卡片先显示工具、命令或文件路径和内容预览,并明确本次授权范围。
|
|
194
|
+
完整操作详情可以展开,状态刷新保留展开状态;ACP 缺少操作输入或单次批准选项
|
|
195
|
+
时禁用批准按钮,仍可拒绝。长内容预览会明确提示缩短,完整参数继续可查看。
|
|
196
|
+
|
|
156
197
|
Codex 交互会话在 thread start/resume 的私有配置中显式开启
|
|
157
198
|
`features.default_mode_request_user_input` 和 `features.request_permissions_tool`,
|
|
158
199
|
使执行模式下的模型能够调用提问和权限请求工具。Web 专用 App Server 的 start、resume、
|
|
@@ -184,19 +225,34 @@ hcc native respond --peer codex-reviewer --request REQUEST_ID --decision accept
|
|
|
184
225
|
hcc native respond --peer codex-reviewer --request REQUEST_ID --decision cancel
|
|
185
226
|
```
|
|
186
227
|
|
|
187
|
-
响应文件只允许 `permissions`、`scope`、`answers`。不能添加原请求没有的路径或
|
|
228
|
+
响应文件只允许 `permissions`、`scope`、`answers`、`content`;MCP 表单用 `content` 对象提交原字段名和类型,例如 `{"content":{"project":"demo","count":2,"enabled":false}}`。不能添加原请求没有的路径或
|
|
188
229
|
网络权限;授予文件权限时必须保留原请求的 deny 条目。所有问题都需明确回答;
|
|
189
230
|
请求参数被截断时,只能拒绝或取消。动态工具与账号 token 刷新尚未接入。
|
|
190
231
|
|
|
191
232
|
Codex MCP 工具审批使用 `mcpServer/elicitation/request`,与命令/文件审批的返回结构
|
|
192
233
|
不同。HCC 对显式 MCP 工具确认提交单次 action/content,不写入 session/always 授权。
|
|
193
|
-
|
|
234
|
+
标准 `form` 模式支持字符串、数值/整数、布尔值、单选和字符串枚举多选,包含标题、说明、默认建议值、必填项、长度/数值/选择数量范围及常用邮箱/URI/date/date-time 格式校验。可选字段只在勾选填写后发送;布尔值需明确选择是或否。字段数量上限 50、单字段选项上限 100、字符串上限 8192 个 UTF-16 单元,表单结构与应答内容各限 65536 字符。
|
|
235
|
+
|
|
236
|
+
Web 刷新执行状态时在页面内存中保留填写内容;提交、请求消失或切换会话后清除,不写入浏览器存储、HCC 事件或投递回执。页面整体重载不会恢复这些答复。此约束针对 HCC 的交互应答路径;provider 自身记录及模型输出继续按其原有行为处理。服务端重复校验内容,审批继续绑定原 executor/session/turn/request;错误输入保留请求供修正。嵌套对象、任意数组、未知约束和 OpenAI 扩展表单模式仍不可批准,页面显示原因并提供拒绝/取消。此能力未改变动态工具或 token 刷新的接入边界。
|
|
237
|
+
|
|
238
|
+
带原 thread/turn 标识的 MCP `url` 请求现在可在 Web 打开授权页面。界面显示 MCP 服务和目标域名,当前控制者明确点击后先保留空白标签页;原执行器接受同一个请求后才跳转,过期或被拒绝的请求会关闭空白页。弹窗被拦截时保留待处理请求,允许弹窗后可重试。仅允许 HTTPS 或 loopback HTTP,拒绝带用户名/密码的 URL、其他协议、缺少 elicitation 标识或被截断的请求;拒绝/取消始终可用。新标签页不保留 opener 或 referrer。loopback 地址需在执行器所在电脑的浏览器访问,HCC 不把本地授权回调代理到另一台设备。
|
|
239
|
+
|
|
240
|
+
打开只回传 `{ "action": "accept" }`,不代表身份认证完成。需在外部页面完成操作,再返回查看原任务的 provider 结果。HCC 不推测授权完成事件,也不在表单中收集凭证;授权 URL、设备码消息、elicitation 标识和元数据仅存在于实时待处理请求,不留在 HCC 交互事件或浏览器存储中。provider 自身日志/历史和外部授权浏览器仍按各自规则处理。账号登录、token 刷新、`openai/userVerification` 与外部授权完成 API 属于独立的未接入能力。
|
|
241
|
+
|
|
242
|
+
浏览器复现:设置 `HCC_ACCEPTANCE_PLAYWRIGHT` 指向 Playwright 模块,再执行 `node scripts/web-mcp-form-acceptance.mjs --run-browser`;`HCC_ACCEPTANCE_CHROME` 可指定 Chrome 路径。该脚本用模拟 provider、真实 HTTP/SQLite/native runtime 和隔离浏览器,不调用模型。表单验收见 `docs/verification/2026-10-02-mcp-form-web-validation.md`。
|
|
243
|
+
|
|
244
|
+
真实模型与浏览器验收使用 `node scripts/web-mcp-form-live-acceptance.mjs --run-live`,同样需要设置 `HCC_ACCEPTANCE_PLAYWRIGHT`,可选 `HCC_ACCEPTANCE_CHROME`、`HCC_ACCEPTANCE_TMUX`、`--codex-bin PATH` 与 `--output NEW_FILE`。默认只打印帮助;显式运行会使用当前模型和账号的额度。脚本让安装版 Codex 调用隔离 stdio MCP 工具,通过实际 Web 操作完成工具确认、字段填写和提交,核对原类型答复、模型文件落盘,以及 Web 关闭后原 native 执行器继续执行;另覆盖 Web-owned App Server 路径,没有注入模型输出或 App Server 请求。
|
|
245
|
+
|
|
246
|
+
此验收分别隔离 HCC 的用户目录、Codex home、项目、tmux socket 和浏览器 profile。已配置的外部认证辅助程序可在原用户目录下只读运行,以保持当前账号的正常凭据获取;不更改原 provider、模型、登录状态或原配置。回执记录源码摘要、实际检查、清理结果及原配置/认证/shell 配置摘要核对,`--output` 必须使用新路径,既有回执不会覆盖。验收工具日志只包含合成表单值,直接答复不应被误当成真实业务数据。
|
|
247
|
+
|
|
194
248
|
|
|
195
249
|
## 当前边界
|
|
196
250
|
|
|
197
251
|
- 尚未实现接管或 attach 已有 Codex/Claude/dsh TUI、桌面会话;这些会话继续使用原
|
|
198
252
|
transport。
|
|
199
|
-
- Web
|
|
253
|
+
- Web 可新建 Codex、Claude、dsh native worker,也可发现并控制同一项目的现有 worker,
|
|
254
|
+
提供消息、回执、中断和明确关闭。“历史”提供 HCC 保留事件与已关闭 worker 的显式恢复;
|
|
255
|
+
记录不是 provider 完整历史,活跃或停止未确认的 worker 不可从此入口恢复。
|
|
200
256
|
关闭页面或 Web runtime 保留独立 native worker;支持与当前执行器、turn 绑定的人工应答。
|
|
201
257
|
使用方式见 [Web 继续本地任务](web-handoff.zh-CN.md#本地-native-worker-接手)。
|
|
202
258
|
- Codex、Claude 和 dsh native worker 自动获得项目与 peer 受限的 HCC MCP;
|
|
@@ -246,8 +302,82 @@ Web 验证覆盖服务与 bridge 控制接口,尚不等于完整浏览器操
|
|
|
246
302
|
|
|
247
303
|
|
|
248
304
|
真实模型与浏览器人工交互可使用 `scripts/web-native-interaction-acceptance.mjs`。
|
|
249
|
-
默认只显示帮助;`--run-live --provider codex|claude|all` 才调用模型。
|
|
305
|
+
默认只显示帮助;`--run-live --provider codex|claude|dsh|all` 才调用模型。
|
|
250
306
|
设置 `HCC_ACCEPTANCE_PLAYWRIGHT`,以及按需设置 `HCC_ACCEPTANCE_CHROME`。
|
|
251
307
|
`--claude-package DIR` 可将已经安装的 SDK 包链接到隔离 worker 项目,由默认加载器
|
|
252
308
|
解析,不注入 query 函数。脚本验证明确批准与拒绝、原会话续接,退出后关闭测试
|
|
253
309
|
进程并清理临时 provider home;使用现有认证和调用额度。它不连接现有用户会话。
|
|
310
|
+
|
|
311
|
+
`--provider dsh --dsh-bin /absolute/path/to/dsh` 使用已安装的公开 launcher 和现有
|
|
312
|
+
`DEEPSEEK_API_KEY`。脚本在私有 ACP profile 中通过公开 `tools/pre-execute` 策略
|
|
313
|
+
让两个指定验收文件的写入请求审批;审批请求来自真实模型工具调用,不注入 ACP 请求。
|
|
314
|
+
验证批准后写入、拒绝后文件不存在、释放 Web 控制后原 session 本地续接,另检查
|
|
315
|
+
桌面和 390px 手机审批卡片。真实结果见 dsh Web 交互回执 (源码目录: `docs/verification/2026-10-02-native-web-dsh-final-snapshot-interactions.json`)。
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
## 安装包验收
|
|
319
|
+
|
|
320
|
+
`scripts/native-installed-acceptance.mjs` 对已经安装的 HCC 包执行验收,通过公开
|
|
321
|
+
`hcc native` 命令启动 daemon 和三个 provider。先把本地包与可选的 Claude SDK
|
|
322
|
+
安装在同一个独立 npm prefix;脚本使用 SDK 默认包解析,不注入 adapter 或 query
|
|
323
|
+
函数。不加 `--run-live` 只显示帮助,不调用模型。
|
|
324
|
+
|
|
325
|
+
```sh
|
|
326
|
+
npm install --prefix /absolute/path/to/acceptance-prefix \
|
|
327
|
+
/absolute/path/to/hello-cc.tgz @anthropic-ai/claude-agent-sdk
|
|
328
|
+
|
|
329
|
+
HCC_ACCEPTANCE_PLAYWRIGHT=file:///absolute/path/to/playwright/index.mjs \
|
|
330
|
+
HCC_ACCEPTANCE_CHROME=/absolute/path/to/chrome \
|
|
331
|
+
node /absolute/path/to/acceptance-prefix/node_modules/@logicseek/hello-cc/scripts/native-installed-acceptance.mjs \
|
|
332
|
+
--run-live --codex-bin /absolute/path/to/codex \
|
|
333
|
+
--dsh-bin /absolute/path/to/dsh --archive /absolute/path/to/hello-cc.tgz \
|
|
334
|
+
--browser --task --output /absolute/path/to/receipt.json
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
验收覆盖三个已安装 provider 的关联回复与 ACK、重复提交、连续上下文、owned
|
|
338
|
+
close/resume、中断,以及一次明确拒绝 Codex 越界写入审批。先通过人工控制入口给每个 worker 授权限定任务,再由模型通过 MCP 沿
|
|
339
|
+
`Codex → Claude → dsh → Codex` 发消息并消费回复。浏览器检查 SDK 默认加载、
|
|
340
|
+
明确批准文件写入、桌面和手机渲染、释放控制权,以及关闭 Web 后原会话本地续接。
|
|
341
|
+
`--task` 增加独立文件协作样例:Codex 实现金额计算,通过五个合同测试,再通过
|
|
342
|
+
模型发出的交接消息让 Claude 写出审查文件。这个样例与生产业务的用户验收分开。
|
|
343
|
+
|
|
344
|
+
脚本使用现有认证和调用额度。HCC 全局 HOME、provider home、tmux server 和项目
|
|
345
|
+
使用私有验收目录;复制到私有配置中的 Codex 凭据命令,仅在读取现有凭据时保留
|
|
346
|
+
原 HOME,原配置保持不变。退出后清理自有进程与临时凭据。回执记录包 SHA-256、
|
|
347
|
+
provider 版本、源码摘要、浏览器证据和清理结果;脚本不会发布 npm 包或部署到
|
|
348
|
+
员工设备。
|
|
349
|
+
|
|
350
|
+
通过已认证的 native CLI/Web 控制入口提交的任务,持久记录为人工请求;共享 HCC
|
|
351
|
+
消息总线送达的内容保持 peer 消息身份,即使发送方自称 `web` 或 `shell`。旧回执
|
|
352
|
+
迁移后仍按 peer 消息处理。来源区分不授予工具权限,写入等受控操作仍需审批。
|
|
353
|
+
委派文件任务时,先由用户明确授权接收 agent 的限定任务,再发送 peer 交接。
|
|
354
|
+
|
|
355
|
+
## 有界稳定性验收
|
|
356
|
+
|
|
357
|
+
安装包验收可加 `--stability`,在基础生命周期和跨 provider 通信之后运行持续负载:
|
|
358
|
+
|
|
359
|
+
```sh
|
|
360
|
+
node /absolute/path/to/acceptance-prefix/node_modules/@logicseek/hello-cc/scripts/native-installed-acceptance.mjs \
|
|
361
|
+
--run-live --codex-bin /absolute/path/to/codex --dsh-bin /absolute/path/to/dsh \
|
|
362
|
+
--archive /absolute/path/to/hello-cc.tgz --stability \
|
|
363
|
+
--stability-cycles 6 --stability-burst 2 --stability-idle-ms 30000 \
|
|
364
|
+
--stability-resume-every 2 --output /absolute/path/to/stability-receipt.json
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
三个 provider 同时工作,每轮先向各 worker 排队投递整组消息。每条要求模型从
|
|
368
|
+
历史中回忆原始随机标记和上一条消息的票据,验证串行处理顺序与上下文保留。
|
|
369
|
+
每轮还重复提交同一提交 ID,核对只产生一条回复与一个 ACK;定期关闭并恢复
|
|
370
|
+
worker,在中点正常重启自有 daemon,再验证原 session 和历史。空闲窗口继续
|
|
371
|
+
检查控制接口、pending 请求与会话身份。结束时核对持久投递、数据库完整性、
|
|
372
|
+
事件保留上限与无回复循环。回执保留每条实际回复、失败状态和自有进程内存
|
|
373
|
+
采样,不自动重放失败任务,也不把同轮重新尝试改写为成功。
|
|
374
|
+
|
|
375
|
+
默认 6 轮、每 worker 每轮 2 条、每轮空闲观察 30 秒、每 2 轮恢复。参数限制为
|
|
376
|
+
1–24 轮、1–4 条、0–300000 毫秒和 1–24 轮恢复间隔;这些选项必须与
|
|
377
|
+
`--stability` 一起使用。这是有界真实模型负载验收,不能代替 24 小时 soak、
|
|
378
|
+
并发容量测量或内存泄漏证明。DSH 单次恢复成功也不能单独解释历史恢复波动。
|
|
379
|
+
|
|
380
|
+
`--stability-only` 与 `--stability` 一起使用时,只建立三个真实会话并运行稳定性
|
|
381
|
+
负载,跳过基础中断、命令审批和模型 MCP 通信场景;回执明确标记该范围。
|
|
382
|
+
适合已有独立生命周期/交互回执时单独补做持续负载,不能把跳过项算作通过。
|
|
383
|
+
发生任一错误时,脚本在关闭自有 worker 前保存会话快照、最近投递和事件。
|
|
@@ -1,6 +1,92 @@
|
|
|
1
|
-
# Web
|
|
1
|
+
# Web 新建 Agent、项目文件与继续本地任务
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Web 可以直接新建 Codex、Claude 或 DeepSeek Harness 后台 Agent,也可以继续同一项目中已有的 native worker 或受管终端。
|
|
4
|
+
|
|
5
|
+
## 浏览文件与产物
|
|
6
|
+
|
|
7
|
+
选择项目后,点击顶部“文件”,即可浏览项目目录并打开已保存的文件,无需先创建 Agent。
|
|
8
|
+
支持逐层进入目录、返回上级、输入项目相对目录和刷新。会话中“引用与执行器能力”的文件
|
|
9
|
+
检索结果也可以直接打开预览;“引用文件”仍然只在消息草稿里加入路径标记。
|
|
10
|
+
|
|
11
|
+
| 文件类型 | 预览方式 |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| 文本、源代码 | 显示转义后的原文 |
|
|
14
|
+
| Markdown | 显示基本排版与代码块,可切回源码 |
|
|
15
|
+
| HTML | 隔离的静态预览,可切回源码;脚本、表单、导航和外部资源不运行 |
|
|
16
|
+
| PNG、JPEG、GIF、WebP | 图片预览 |
|
|
17
|
+
| PDF | 浏览器内置查看器;未支持内嵌显示时可下载查看 |
|
|
18
|
+
| SVG | 仅显示源码 |
|
|
19
|
+
| 其他二进制文件 | 提示暂不支持预览,不尝试按文本显示 |
|
|
20
|
+
|
|
21
|
+
预览只读取当前项目内的普通文件,不修改文件,也不会把内容上传给模型。
|
|
22
|
+
`dist`、`build` 等产物目录可以浏览;运行状态、依赖缓存及已知凭据路径不提供预览,
|
|
23
|
+
符号链接和硬链接也不读取。目录每次最多显示 500 项,并提示未完整列出的情况;
|
|
24
|
+
文本超过 1 MiB 时只显示前部并标记截断,截断 HTML 只显示源码。图片和 PDF 最大为
|
|
25
|
+
10 MiB,超过限制会明确提示。文件在读取期间变化时,请刷新后重试。
|
|
26
|
+
|
|
27
|
+
切换文件、切换项目或关闭预览会使旧请求失效。手机可在目录与预览之间返回切换;
|
|
28
|
+
分屏辅助窗口的文件入口会在同一项目的主窗口中打开。静态预览不会启动生成网页所需的
|
|
29
|
+
开发服务器。
|
|
30
|
+
|
|
31
|
+
## 上传与编辑项目文件
|
|
32
|
+
|
|
33
|
+
在“文件”中进入目标目录,选择一个本机文件并核对目标文件名,再点击上传。文件会保存到
|
|
34
|
+
运行 HCC 的机器上当前项目的这个目录,单文件最大 10 MiB;不自动创建目录,不覆盖同名
|
|
35
|
+
文件。上传不是聊天附件发送,不会自动让 Agent 读取文件。要在任务中引用文件,仍需在
|
|
36
|
+
消息中明确引用项目路径。
|
|
37
|
+
|
|
38
|
+
完整的 UTF-8 文本、源码、Markdown 和 HTML 可以切换到编辑模式,修改后显式保存。
|
|
39
|
+
编辑上限为 1 MiB,截断预览和二进制文件不能在线编辑。UTF-8 BOM 与原有 CRLF 换行会
|
|
40
|
+
保留;混合换行文件会提示保存时统一为 LF。没有编辑过的文本不能重复保存。
|
|
41
|
+
保存前核对读取时的文件版本;
|
|
42
|
+
另一窗口或本地程序已修改文件时,保留草稿并显示冲突,核对磁盘内容后再决定如何处理。
|
|
43
|
+
HCC 的同文件写入会串行化;本地编辑器等其他程序不共享这个锁,因此这不是对任意外部
|
|
44
|
+
写入的系统级原子版本交换。保存通过同目录临时文件替换,避免向读者暴露半写的文本。
|
|
45
|
+
|
|
46
|
+
切换文件、项目或关闭文件窗口会保留当前页面内的编辑草稿;刷新或关闭整个页面仍可能
|
|
47
|
+
丢失未保存内容。“返回预览”保留草稿,“放弃草稿并重载”会先确认再丢弃。
|
|
48
|
+
遇到断线或写入回执不确定时,使用“读取已保存文件”核对文本,或“核对目标文件”比较
|
|
49
|
+
上传文件的大小和内容哈希;不会自动重发保存或上传。上传回执恢复只在浏览器保存项目
|
|
50
|
+
身份、路径、大小和哈希,不保存上传文件内容。
|
|
51
|
+
|
|
52
|
+
上传、编辑与预览沿用相同的项目路径限制,不允许修改运行状态、依赖缓存、已知凭据路径、
|
|
53
|
+
符号链接或硬链接。写入固定到经验证的目标父目录身份,不会跟随被替换的项目路径去写
|
|
54
|
+
另一个目录;如果原目录在写入中被移动,需重新选择当前位置并核对写入结果。
|
|
55
|
+
|
|
56
|
+
## 项目 Agent 启动默认值
|
|
57
|
+
|
|
58
|
+
顶部“设置”中可保存当前项目的默认 Agent,以及 Codex、Claude、DeepSeek Harness
|
|
59
|
+
各自的默认模型和工作目录。它们保存在所选项目的 HCC 数据库中,可供其他浏览器读取;
|
|
60
|
+
语言、主题、密度和字号仍是当前浏览器的显示偏好。
|
|
61
|
+
|
|
62
|
+
模型留空表示使用 provider 自身的当前配置;HCC 不会推测该配置中的模型,也不在保存时
|
|
63
|
+
调用模型验证名称。工作目录保存为项目相对路径,`.` 表示项目根目录,其他值必须指向
|
|
64
|
+
现有的项目内目录。新建时会再次检查目录,已经删除或移到项目外的目录不能用来启动。
|
|
65
|
+
|
|
66
|
+
保存后,“新建 Agent”会预填相应 provider 的模型和目录,本次创建仍可修改。取消后再打开
|
|
67
|
+
会保留尚未提交的草稿;默认值读取或重试不会覆盖已编辑的字段。成功创建后,下一次新建
|
|
68
|
+
重新读取项目默认值。清空模型表示本次使用 provider 默认配置,可以覆盖已保存的项目模型。
|
|
69
|
+
新值只用于后续 Web 新建 native worker;既有 worker、历史恢复、CLI 启动及高级终端/
|
|
70
|
+
App Server 流程各自沿用原有配置。此处不管理 provider 登录、API key、端点、环境变量
|
|
71
|
+
或全局配置文件。
|
|
72
|
+
|
|
73
|
+
保存使用版本校验。其他窗口先保存后,当前窗口会显示冲突并保留输入,需重新载入并
|
|
74
|
+
核对最新值;不会静默覆盖其他窗口的修改。“恢复初始值”先重置表单,保存后才生效。
|
|
75
|
+
如果保存响应因断线而不确定,先重新读取配置核对结果。
|
|
76
|
+
|
|
77
|
+
## 新建后台 Agent
|
|
78
|
+
|
|
79
|
+
运行 `hcc web`,选择项目,再点击“新建 Agent”。选择 Codex、Claude 或 DeepSeek Harness 后,默认使用“后台 Agent”;无需预先运行 `hcc native start`。对应 CLI 或 Claude SDK 仍需已安装,身份认证沿用运行 hello-cc 的环境,Web 不代为安装或登录。
|
|
80
|
+
|
|
81
|
+
工作目录使用该项目为此 provider 保存的默认值,未设置时为项目根目录,可改为项目内的子目录;worker 仍共享所选项目的任务、消息、锁和交接。需要在另一个项目工作时,先切换或添加该项目。模型预填项目中保存的默认值,也可在本次创建时修改或清空;留空使用 provider 当前配置,填写时应使用该 provider 支持的模型值。名称可留空自动生成。
|
|
82
|
+
|
|
83
|
+
“新建 Agent”用于创建新的 native worker;恢复已关闭的 worker,请使用项目栏“历史”中的“HCC 保留历史”。既有 `hcc native start` 和 `--resume last` CLI 继续可用。创建后在同一 Web 会话内发送提示、查看回执和处理审批;创建成功不代表已经运行模型任务。关闭页面或停止 Web runtime 都不会停止独立的 native runtime/worker,需要明确执行关闭操作。
|
|
84
|
+
|
|
85
|
+
“高级选项”保留终端 CLI、Codex 的结构化 App Server 及它们原有的恢复流程。Shell 使用终端,DeepSeek Harness 使用后台 Agent。以下交接说明分别适用于这些执行方式。
|
|
86
|
+
|
|
87
|
+
## 继续已有终端
|
|
88
|
+
|
|
89
|
+
CLI/tmux 适合继续已经托管的本地 Codex/Claude/shell:Web 打开同一个 pane,不另起执行器。
|
|
4
90
|
|
|
5
91
|
运行 `hcc web` 后选择已有会话。选中项和未发送草稿按项目保存于当前浏览器;刷新会恢复原位置。第一个 Web 连接取得控制,其他窗口可观察,点击“接管浏览器控制”后才可写入。服务端检查控制 epoch,旧窗口不能继续输入、改变终端尺寸、修改该 peer 或处理审批。本地 tmux client 仍可直接输入,Web 会显示其连接状态。
|
|
6
92
|
|
|
@@ -10,13 +96,19 @@
|
|
|
10
96
|
|
|
11
97
|
## Codex 结构化界面
|
|
12
98
|
|
|
13
|
-
|
|
99
|
+
在“新建 Agent”中选择 Codex,展开“高级选项”并选择结构化 App Server。需要本地已安装且支持 App Server 的 `codex`,登录和模型环境来自启动 hello-cc 的进程。hello-cc 不自动登录、不更改信任配置、不探测未公开的 TUI 内部 endpoint。
|
|
14
100
|
|
|
15
101
|
可先运行 `hcc doctor --codex --json` 查看只读诊断。它分别报告已安装版本、CLI help 声明的 App Server 启动参数、hooks 配置与项目中的 hook 调用记录;这些事实不等于完整 RPC 能力、hooks 已受信任、stdout 投递成功或模型已接收。版本/help 探测使用独立临时 HOME/CODEX_HOME 并清理,防止 Codex 启动文件触碰用户目录;hooks 配置仍从原路径只读检查。没有充分回执的状态显示 `unknown`,不会自动触发 hook 或修改 trust。普通 `hcc doctor` 仍只检查数据库。
|
|
16
102
|
|
|
103
|
+
升级 Codex 前可运行 `npm run codex:protocol -- --codex-bin /absolute/path/to/codex --out /tmp/hcc-protocol-new`。输出目录必须不存在;工具使用隔离 HOME/CODEX_HOME 生成官方 TypeScript 和 JSON Schema,记录版本/文件指纹并检查交接所依赖的协议子集。不兼容时返回非零退出码,未接入请求单独列出;生成成功不代表真实模型或外部授权验收。安装包内也可直接运行 `node /absolute/path/to/hello-cc/scripts/codex-protocol.mjs`。详见 `docs/codex-protocol.md`。
|
|
104
|
+
|
|
17
105
|
结构化界面提供消息、当前 turn 状态、追加指令、轮次中断、计划、差异和人工交互。命令/文件审批以及空表单 MCP 工具确认由当前控制窗口明确批准本次或拒绝。文件与网络权限可逐项勾选,并明确选择本轮或会话有效期;只能授予原请求的子集。问题支持选项、其他/自由输入和敏感答案,需逐题明确填写。接管控制本身不会批准工具。
|
|
18
106
|
|
|
19
|
-
表单输入与焦点会跨状态刷新保留,直接答案不写入 HCC 状态、事件、回执或浏览器存储。原 turn 完成、中断成功、provider 解决请求或执行器关闭后,请求卡片失效;旧控制窗口不能用过期 epoch
|
|
107
|
+
表单输入与焦点会跨状态刷新保留,直接答案不写入 HCC 状态、事件、回执或浏览器存储。原 turn 完成、中断成功、provider 解决请求或执行器关闭后,请求卡片失效;旧控制窗口不能用过期 epoch 应答。参数被截断时只能拒绝或取消。MCP 支持下述标准表单和带原 thread/turn 标识的 URL 请求;嵌套对象、任意数组等复杂结构、动态工具及账号 token 刷新尚未接入。
|
|
108
|
+
|
|
109
|
+
MCP URL 请求显示授权目标,当前控制窗口点击“打开授权页面”后,原执行器接受请求才跳转。弹窗被拦截时不提交请求;过期请求不会打开授权地址。仅允许 HTTPS 或 loopback HTTP,链接带用户名/密码、其他协议、请求标识缺失或参数截断时保留拒绝/取消入口。loopback 地址需在执行器所在电脑打开,其他设备无法通过 HCC 代理本地授权页。
|
|
110
|
+
|
|
111
|
+
打开页面只表示同意发起外部流程,不表示认证成功。请在外部页面完成操作,再返回关注原任务结果;新页面不保留 opener/referrer。URL、设备码消息和元数据不进入 HCC 交互事件或浏览器存储,实时待处理请求仍可供控制窗口查看。账号登录、token 刷新和 OpenAI 用户验证扩展不包含在此能力内。
|
|
20
112
|
|
|
21
113
|
运行中发消息使用 steer;空闲时开始新 turn。中断当前轮与终止执行器是不同操作。turn 完成不自动把 hcc task 标记为验收完成。
|
|
22
114
|
|
|
@@ -26,9 +118,13 @@
|
|
|
26
118
|
|
|
27
119
|
关闭浏览器后 App Server 仍由 hello-cc runtime 管理;停止 runtime 会关闭它。新 runtime 不会自动重启 App Server 或重放未确认消息,可以从已保存 thread 显式恢复。
|
|
28
120
|
|
|
121
|
+
MCP 标准表单可以直接在 Web 填写文本、数值、是/否和单选/多选;两种执行器共用校验,答复仍回到同一请求。状态刷新保留页面内的填写内容,可选项不自动发送默认值;页面重载会清空答复。未支持的模式或结构会说明原因,保留拒绝/取消入口。实现和验收范围见 `docs/verification/2026-10-02-mcp-form-web-validation.md`。
|
|
122
|
+
|
|
123
|
+
真实模型复现脚本为 `scripts/web-mcp-form-live-acceptance.mjs --run-live`:先由本地 Codex 实际发起 MCP 交互,再从桌面/手机 Web 提交,核对同一 native 执行器继续完成和交回本地;另覆盖 Web-owned App Server。环境变量与隔离/账号范围见 `docs/native.zh-CN.md` 的真实模型与浏览器验收说明。成功以该次回执为准,默认运行只打印帮助,不调用模型。
|
|
124
|
+
|
|
29
125
|
## 本地 native worker 接手
|
|
30
126
|
|
|
31
|
-
|
|
127
|
+
已有 worker 可以继续从 CLI 启动,例如 `hcc native start --peer codex-worker --provider codex`,再打开 Web 的同一项目;也可直接使用上方的新建入口。Web 自动发现实际仍由 native runtime 持有的 worker,显示其原 peer/session、事件和投递回执;接手已有 worker 后的发送、中断和明确关闭都通过原 runtime 执行,不另建 provider 子进程。Claude/dsh worker 也走这条路径,按实际能力显示中断操作。
|
|
32
128
|
|
|
33
129
|
发送成功先显示队列回执;执行器接收、运行和完成分别使用实际投递状态。断线或不确定结果保留 submission ID,刷新不会重放消息。native runtime 重启或 worker 被替换时,旧 Web 视图及其控制凭证失效,重新发现当前 worker 后才能操作。
|
|
34
130
|
|
|
@@ -38,16 +134,30 @@
|
|
|
38
134
|
|
|
39
135
|
## 历史、协作工具与结果审阅
|
|
40
136
|
|
|
41
|
-
|
|
137
|
+
项目栏“历史”默认打开“HCC 保留历史”,可按 Codex、Claude、DeepSeek Harness 筛选当前项目的 native worker,查看已保留的 provider 事件与投递回执。native runtime 离线时仍可读取已保存记录;浏览历史不会启动 provider 或模型 turn。
|
|
138
|
+
|
|
139
|
+
worker 列表最多显示最近 100 项,超过时提示截断。事件每页 100 条,可以前后翻页;投递回执显示该 worker 最新 100 条。当前存储只保留整个项目最近约 2,000 条 provider 事件;这不是 provider 的完整对话档案。历史中可能没有最初输入、早期已裁剪事件或尚未被 HCC 记录的输出。DSH ACP 恢复本身也不代表原始对话重放。
|
|
140
|
+
|
|
141
|
+
恢复前先明确关闭原 worker,再选中历史项并确认。后端只接受已记录为 `closed`、原 peer/provider/session 与 owner 仍一致的记录;运行中、断连、失败或退出未确认的记录不能从此入口恢复。恢复沿用原 peer、provider 会话和工作目录,创建新的 native 执行器;不会重放已处理或投递状态不明的消息,尚未执行的队列消息会按现有 native 队列规则继续。provider 安装和账号要求仍然适用,DSH 还需实际 ACP runtime 声明 resume 能力。
|
|
142
|
+
|
|
143
|
+
恢复请求只提交一次。断线或响应丢失后,页面保留原恢复记录,通过刷新查找同一 peer 的新执行器;不会自动重新恢复。浏览器刷新后也可继续检查结果。恢复成功仅表示执行器已接入,Claude SDK 的会话初始化仍可能等到第一条新提示后才确认。
|
|
144
|
+
|
|
145
|
+
选择“Codex 已保存会话”,可分页浏览当前项目已保存的 thread,读取上下文,再显式恢复或分叉。恢复仍要求旧执行器已确认停止;分叉生成新的 thread/peer,原任务 owner 不变。有正在托管的源会话时,分叉也必须取得该会话的浏览器控制。历史读取不会启动模型 turn。
|
|
42
146
|
|
|
43
147
|
Web 专用 Codex App Server,以及由 HCC 托管的 Codex/Claude/dsh native worker,自动接入 [项目与 peer 受限的 MCP 协作工具](mcp.zh-CN.md)。配置只传给对应执行器或 worker,不写全局 provider 配置;关闭 worker 前撤销其临时权限。模型可查询任务与 inbox、领取任务、发送消息、写 handoff、获取/释放自己的资源锁和记录本地证据;不替用户执行发布或业务验收。
|
|
44
148
|
|
|
45
|
-
会话栏“结果审阅”汇总结构化 command
|
|
149
|
+
会话栏“结果审阅”汇总结构化 command 的执行状态与退出码、是否有 turn 差异、模型通过 MCP 明确提交的本地证据,以及人工添加的验收记录。自动结果仅在实时观察到新 turn 开始后归属当前任务;缺失该事件时,不会从历史快照补认任务证据。自动结果在项目数据库 events 中只保存中性标题、状态、退出码和来源 ID,不保存命令、输出或差异正文;正文仍可在可用的执行器会话或 provider 历史中查看。命令退出成功仅说明该命令成功;人工填写“通过”必须附证据引用。界面分别展示本地验证、发布部署、业务验收,并注明记录来源。turn 完成、测试记录或人工验收均不自动改变 hcc task 状态。`gc --history` 保留结果审计记录和最小提交去重凭据。
|
|
150
|
+
|
|
151
|
+
## Codex 账号与限额
|
|
152
|
+
|
|
153
|
+
Web 专用 Codex 和原生 Codex worker 新增只读“账号与限额”面板,观察窗口也可刷新。它显示本执行器的登录/供应商认证状态、可获取的订阅窗口、重置时间和读取时间;缺失或不支持的配额保持未知,账号切换与执行器替换拒绝旧查询结果。此操作不新建任务或 turn,也不提供登录、退出或 token 管理。未登录时需在运行任务的电脑完成本地 Codex 登录。使用方式、接口身份和真实/模拟验收边界见 [账号与限额说明](codex-account.zh-CN.md)。
|
|
46
154
|
|
|
47
155
|
## 验收边界
|
|
48
156
|
|
|
157
|
+
以下既有记录分别对应当时的执行器、交接和交互流程,不代表新增的统一“新建 Agent”、项目启动默认值、文件上传编辑、HCC 历史或 Web native 恢复入口已完成真实模型或发布验收。
|
|
158
|
+
|
|
49
159
|
本地验证包含真实 SQLite/HTTP、模拟交互请求、隔离 tmux 与桌面/手机浏览器。安装版 Codex 0.144.6 的协议验收另行覆盖 initialize、thread/start/list、10 个 MCP 工具发现和实际 `hcc_state` 读回;此协议检查不调用模型,可用 `node scripts/web-handoff-installed-acceptance.mjs` 重现。
|
|
50
160
|
|
|
51
|
-
真实模型验收已在隔离项目和 Codex home 中完成“本地 → Web → 本地”三段文件任务,全程保持原 Codex 进程和 thread;关闭 Web runtime 后仍可继续。可用 `scripts/web-native-model-acceptance.mjs` 在明确需要真实模型调用时重现。三种 provider 的真实生命周期、模型 MCP 发信、回复/ACK 和无回复循环另有独立回执。交互表单另有 11 项模拟 provider 浏览器检查。真实 Codex 已经完成“提问 → Web 答复 → 指定文件权限 → 本轮授权 → 写入所选答案 → 后续请求拒绝 → 本地继续”的验收;默认加载的 Claude SDK 已完成真实 Write 工具批准、拒绝和本地续接。dsh
|
|
161
|
+
真实模型验收已在隔离项目和 Codex home 中完成“本地 → Web → 本地”三段文件任务,全程保持原 Codex 进程和 thread;关闭 Web runtime 后仍可继续。可用 `scripts/web-native-model-acceptance.mjs` 在明确需要真实模型调用时重现。三种 provider 的真实生命周期、模型 MCP 发信、回复/ACK 和无回复循环另有独立回执。交互表单另有 11 项模拟 provider 浏览器检查。真实 Codex 已经完成“提问 → Web 答复 → 指定文件权限 → 本轮授权 → 写入所选答案 → 后续请求拒绝 → 本地继续”的验收;默认加载的 Claude SDK 已完成真实 Write 工具批准、拒绝和本地续接。dsh 已完成真实 ACP 写入的 Web 批准、拒绝和原 session 本地续接,审批卡片另通过桌面与 390px 手机检查;仅在隔离 profile 中对指定验收文件设置公开审批策略。完整结果与运行条件见 本地验收记录 (源码目录: `docs/verification/2026-10-02-web-local-task-handoff.md`)。
|
|
52
162
|
|
|
53
163
|
任意未托管 TUI/普通终端的活动执行器迁移、私有 daemon endpoint、任意协议版本的完整兼容矩阵,以及发布安装和真实业务验收仍在本次证据范围之外。
|
package/lib/cli/app.mjs
CHANGED
|
@@ -90,6 +90,9 @@ import { assignTeamWorkers, expandTeamWorkers, inferTeamItems } from '../core/co
|
|
|
90
90
|
import { autoPeerBasis, autoPeerKind, autoPeerProviderSession, autoPeerResumeId, autoPeerSessionId, readAncestorCliInfo, resolveCurrentPeer, resumeIdFromArgs, shortHash } from '../integrations/peers/identity.mjs';
|
|
91
91
|
import { inspectProviderProcess } from '../integrations/peers/processes.mjs';
|
|
92
92
|
import { registerProjectActivity } from '../runtime/projects.mjs';
|
|
93
|
+
import { migrateLegacyProjectState } from '../runtime/state-migration.mjs';
|
|
94
|
+
import { projectDbPath } from '../runtime/paths.mjs';
|
|
95
|
+
import { ensureDshIntegration } from '../integrations/dsh.mjs';
|
|
93
96
|
|
|
94
97
|
// Lazy-load lib modules (they may import node-pty which needs to be optional)
|
|
95
98
|
const _libDir = path.resolve(fileURLToPath(import.meta.url), '..', '..');
|
|
@@ -505,8 +508,9 @@ function webErrorStatus(err) {
|
|
|
505
508
|
if (!(err instanceof CliError)) return 500;
|
|
506
509
|
if (err.code === 'REGISTRY_BUSY') return 503;
|
|
507
510
|
if (err.code === 'CODEX_START_FAILED') return 503;
|
|
511
|
+
if (err.code === 'PROJECT_PATH_CHANGED') return 409;
|
|
508
512
|
if (err.code.startsWith('CODEX_') || ['STALE_CONTROL_EPOCH', 'UNKNOWN_CONTROL_CLIENT'].includes(err.code)) return 409;
|
|
509
|
-
if (['BAD_ARGS', 'BAD_REQUEST', 'PEER_IDENTITY_REQUIRED', 'REQUEST_TOO_LARGE'].includes(err.code)) return 400;
|
|
513
|
+
if (['BAD_ARGS', 'BAD_REQUEST', 'PEER_IDENTITY_REQUIRED', 'REQUEST_TOO_LARGE', 'INTERACTION_RESPONSE_INVALID'].includes(err.code)) return 400;
|
|
510
514
|
if (['PEER_IDENTITY_MISMATCH', 'TASK_OWNED', 'TASK_OWNER_MISMATCH', 'LOCK_OWNED', 'PROJECT_NOT_REGISTERED', 'PROJECT_PATH_FORBIDDEN', 'RUNTIME_ADMIN_REQUIRED'].includes(err.code)) return 403;
|
|
511
515
|
if (err.code.startsWith('NATIVE_')) return err.code === 'NATIVE_RUNTIME_OFFLINE' ? 503 : 409;
|
|
512
516
|
if (['NOT_FOUND'].includes(err.code)) return 404;
|
|
@@ -574,11 +578,49 @@ function formatHookEventName(hookType) {
|
|
|
574
578
|
}
|
|
575
579
|
|
|
576
580
|
function writeGuidance(ctx) {
|
|
577
|
-
return writeGuidanceForRoot(ctx.root);
|
|
581
|
+
return writeGuidanceForRoot(ctx.root, { expectedSnapshot: ctx.initialRootIdentity });
|
|
578
582
|
}
|
|
579
583
|
|
|
580
|
-
function removeGuidanceBlocks(ctx) {
|
|
581
|
-
return removeGuidanceBlocksForRoot(ctx.root
|
|
584
|
+
function removeGuidanceBlocks(ctx, options = {}) {
|
|
585
|
+
return removeGuidanceBlocksForRoot(ctx.root,
|
|
586
|
+
{ expectedSnapshot: ctx.initialRootIdentity, ...options });
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function cmdMigrateState(ctx, args) {
|
|
590
|
+
if (wantsHelp(args)) {
|
|
591
|
+
console.log(`${CLI_NAME} migrate-state --offline --yes\n\n` +
|
|
592
|
+
'Stop all old hello-cc Web, Native, PTY, tmux, hook and external database writers first. ' +
|
|
593
|
+
'This command verifies known process evidence, snapshots SQLite including WAL, and leaves the old directory untouched.');
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
const opts = parseOpts(args, { booleans: ['offline', 'yes'] });
|
|
597
|
+
validateOpts('migrate-state', opts, ['offline', 'yes']);
|
|
598
|
+
if (opts.offline !== true || opts.yes !== true) {
|
|
599
|
+
throw new CliError('STATE_MIGRATION_OFFLINE_REQUIRED',
|
|
600
|
+
'Stop every old project-state writer, then acknowledge downtime with migrate-state --offline --yes');
|
|
601
|
+
}
|
|
602
|
+
const result = migrateLegacyProjectState(ctx.root, {
|
|
603
|
+
confirmedOffline: true,
|
|
604
|
+
// The operator's explicit --offline assertion covers external writers
|
|
605
|
+
// that cannot be discovered reliably across supported platforms. The
|
|
606
|
+
// migrator still checks known runtime, PTY and SQLite peer evidence.
|
|
607
|
+
assertOffline: () => true
|
|
608
|
+
});
|
|
609
|
+
let dshRebuilt = false;
|
|
610
|
+
if (result.dsh) {
|
|
611
|
+
try {
|
|
612
|
+
ensureDshIntegration({ ...ctx, dbPath: projectDbPath(ctx.root) }, { mode: result.dsh.mode });
|
|
613
|
+
dshRebuilt = true;
|
|
614
|
+
} catch (error) {
|
|
615
|
+
throw new CliError('STATE_MIGRATION_DSH_REBUILD_REQUIRED',
|
|
616
|
+
`Project state migrated to ${result.stateDir}, but DSH configuration needs rebuilding. ` +
|
|
617
|
+
`Run ${result.dsh.rebuildCommand}. Original data remains at ${result.sourceDir}.`,
|
|
618
|
+
{ cause: error });
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
printResult(ctx, { ...result, dsh_rebuilt: dshRebuilt },
|
|
622
|
+
() => `project state migrated: ${result.stateDir}\nlegacy source kept: ${result.sourceDir}` +
|
|
623
|
+
(dshRebuilt ? '\nDSH integration rebuilt for the new private path' : ''));
|
|
582
624
|
}
|
|
583
625
|
|
|
584
626
|
// ─── hcc doctor ─────────────────────────────────────────────────────────────
|
|
@@ -593,6 +635,7 @@ async function dispatch(ctx, rest) {
|
|
|
593
635
|
if (command === 'update') return cmdUpdate(ctx, args);
|
|
594
636
|
if (command === 'uninstall') return cmdUninstall(ctx, args);
|
|
595
637
|
if (command === 'init') return cmdInit(ctx, args);
|
|
638
|
+
if (command === 'migrate-state') return cmdMigrateState(ctx, args);
|
|
596
639
|
if (command === 'register') return cmdRegister(ctx, args);
|
|
597
640
|
if (command === 'join') return cmdJoin(ctx, args);
|
|
598
641
|
if (command === 'env') return cmdEnv(ctx, args);
|
|
@@ -163,8 +163,13 @@ export function createCoordinationCommands(deps) {
|
|
|
163
163
|
const kind = opts.kind || 'ask';
|
|
164
164
|
const runtime = opts.inject ? readRuntime(ctx) : null;
|
|
165
165
|
const db = connect(ctx);
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
let id;
|
|
167
|
+
try {
|
|
168
|
+
touchCurrentPeer(db, ctx, identity, null, 'shell');
|
|
169
|
+
id = sendMessage(db, sender, recipient, taskId, kind, body);
|
|
170
|
+
} finally {
|
|
171
|
+
db.close();
|
|
172
|
+
}
|
|
168
173
|
let injected = false;
|
|
169
174
|
if (opts.inject) {
|
|
170
175
|
await injectPeer(ctx, recipient, body, !opts['no-enter'], runtime, sender);
|
|
@@ -184,8 +189,13 @@ export function createCoordinationCommands(deps) {
|
|
|
184
189
|
const kind = opts.kind || 'broadcast';
|
|
185
190
|
const runtime = opts.inject ? readRuntime(ctx) : null;
|
|
186
191
|
const db = connect(ctx);
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
let id;
|
|
193
|
+
try {
|
|
194
|
+
touchCurrentPeer(db, ctx, identity, null, 'shell');
|
|
195
|
+
id = sendMessage(db, sender, 'all', taskId, kind, body);
|
|
196
|
+
} finally {
|
|
197
|
+
db.close();
|
|
198
|
+
}
|
|
189
199
|
let injected = 0;
|
|
190
200
|
let skipped = 0;
|
|
191
201
|
if (opts.inject) {
|
package/lib/cli/commands/dsh.mjs
CHANGED
|
@@ -14,7 +14,7 @@ function defaultHelp() {
|
|
|
14
14
|
' hcc dsh status [--dsh-bin PATH]',
|
|
15
15
|
' hcc dsh web [--mode hooks|cordis|off] [--dsh-bin PATH] [--dsh-home PATH] -- [dsh web arguments]',
|
|
16
16
|
'',
|
|
17
|
-
'Setup writes
|
|
17
|
+
'Setup writes managed configuration under the selected private state directory. Modes: hooks (default), cordis (native tools), off.',
|
|
18
18
|
'Web starts the official dsh web runtime; its real sessions join hello-cc through the selected integration.',
|
|
19
19
|
'Pass runtime arguments after --, for example: hcc dsh web -- --port 8080',
|
|
20
20
|
'Show dsh web help: hcc dsh web -- --help',
|
package/lib/cli/commands/gc.mjs
CHANGED
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
} from '../../core/coordination/gc-plan.mjs';
|
|
26
26
|
import { runOptimisticEvidenceMutation } from '../../core/coordination/optimistic-evidence.mjs';
|
|
27
27
|
import { peerEvidenceAllowsReap } from '../../core/peers/evidence.mjs';
|
|
28
|
-
import {
|
|
28
|
+
import { globalRuntimePath } from '../../runtime/paths.mjs';
|
|
29
|
+
import { resolveProjectDatabase } from '../../runtime/project-path.mjs';
|
|
29
30
|
import { readRuntime, reclaimRuntimePointerFiles } from '../../runtime/state.mjs';
|
|
30
31
|
import { runtimeRequest, runtimeBufferGcUnavailable } from '../../runtime/client.mjs';
|
|
31
32
|
import { collectBufferEvidence } from '../../runtime/buffer-evidence.mjs';
|
|
@@ -57,6 +58,10 @@ export function createGcCommands(deps) {
|
|
|
57
58
|
// stale bufs) so automatic background gc bounds DB growth without deleting
|
|
58
59
|
// user-meaningful history.
|
|
59
60
|
// `db` is used open; the caller owns its lifecycle.
|
|
61
|
+
function bufferDirectory(ctx) {
|
|
62
|
+
return path.join(resolveProjectDatabase({ root: ctx.root, createStateDir: false }).stateDir, BUFS_DIR_NAME);
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
function captureGcClockSubject(db, {
|
|
61
66
|
bufferGcCutoffs,
|
|
62
67
|
olderThanDays,
|
|
@@ -263,12 +268,16 @@ function captureRequiredBufferDirectoryComponent(component, description) {
|
|
|
263
268
|
function captureOptionalBufferDirectory(root, directoryName) {
|
|
264
269
|
const requestedRoot = path.resolve(root);
|
|
265
270
|
const canonicalRoot = fs.realpathSync.native(requestedRoot);
|
|
266
|
-
const stateDirectory =
|
|
271
|
+
const stateDirectory = resolveProjectDatabase({ root: canonicalRoot, createStateDir: false }).stateDir;
|
|
267
272
|
const directory = path.join(stateDirectory, directoryName);
|
|
268
273
|
const components = [
|
|
269
|
-
captureRequiredBufferDirectoryComponent(canonicalRoot, 'Project root')
|
|
270
|
-
captureRequiredBufferDirectoryComponent(stateDirectory, 'Project state directory')
|
|
274
|
+
captureRequiredBufferDirectoryComponent(canonicalRoot, 'Project root')
|
|
271
275
|
];
|
|
276
|
+
try {
|
|
277
|
+
components.push(captureRequiredBufferDirectoryComponent(stateDirectory, 'Project state directory'));
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
280
|
+
}
|
|
272
281
|
|
|
273
282
|
let stat;
|
|
274
283
|
try {
|
|
@@ -623,10 +632,6 @@ function runGcWithHistorySnapshot(ctx, db, {
|
|
|
623
632
|
return results;
|
|
624
633
|
}
|
|
625
634
|
|
|
626
|
-
function bufferDirectory(ctx) {
|
|
627
|
-
return path.resolve(path.join(ctx.root, '.hello-cc', BUFS_DIR_NAME));
|
|
628
|
-
}
|
|
629
|
-
|
|
630
635
|
function bufferDirectoryPaths(directory) {
|
|
631
636
|
try {
|
|
632
637
|
return fs.readdirSync(directory).map((name) => path.resolve(directory, name));
|
|
@@ -654,16 +659,16 @@ function localBufferEvidence(ctx, db, directory, unknownTracker = null, candidat
|
|
|
654
659
|
});
|
|
655
660
|
}
|
|
656
661
|
|
|
657
|
-
function runtimePointerPresent(
|
|
662
|
+
function runtimePointerPresent(localPointer) {
|
|
658
663
|
return Boolean(process.env.HCC_RUNTIME_URL ||
|
|
659
|
-
fs.existsSync(
|
|
664
|
+
fs.existsSync(localPointer) ||
|
|
660
665
|
fs.existsSync(globalRuntimePath()));
|
|
661
666
|
}
|
|
662
667
|
|
|
663
|
-
function reclaimUnavailableRuntimePointers(
|
|
668
|
+
function reclaimUnavailableRuntimePointers(localPointer, { dryRun = false } = {}) {
|
|
664
669
|
if (process.env.HCC_RUNTIME_URL) return { allowed: false, gcCutoffs: [] };
|
|
665
670
|
const gcCutoffs = [];
|
|
666
|
-
const result = reclaimRuntimePointerFiles([
|
|
671
|
+
const result = reclaimRuntimePointerFiles([localPointer, globalRuntimePath()], {
|
|
667
672
|
dryRun,
|
|
668
673
|
onReclaim: ({ gcCutoff }) => {
|
|
669
674
|
if (Number.isSafeInteger(gcCutoff)) gcCutoffs.push(gcCutoff);
|
|
@@ -713,15 +718,17 @@ function deferredPreparedBufferGc(prepared, graceActive = false) {
|
|
|
713
718
|
}
|
|
714
719
|
|
|
715
720
|
async function prepareManualBufferGc(ctx, db, { retentionSec, dryRun }) {
|
|
716
|
-
const
|
|
721
|
+
const stateDir = resolveProjectDatabase({ root: ctx.root, createStateDir: false }).stateDir;
|
|
722
|
+
const directory = path.join(stateDir, BUFS_DIR_NAME);
|
|
723
|
+
const localPointer = path.join(stateDir, 'runtime.json');
|
|
717
724
|
const unknownTracker = new Map();
|
|
718
725
|
const pointerGcCutoffs = [];
|
|
719
726
|
const recoverRuntimePointers = () => {
|
|
720
|
-
const recovery = reclaimUnavailableRuntimePointers(
|
|
727
|
+
const recovery = reclaimUnavailableRuntimePointers(localPointer, { dryRun });
|
|
721
728
|
pointerGcCutoffs.push(...recovery.gcCutoffs);
|
|
722
729
|
return recovery.allowed;
|
|
723
730
|
};
|
|
724
|
-
const pointerPresent = runtimePointerPresent(
|
|
731
|
+
const pointerPresent = runtimePointerPresent(localPointer);
|
|
725
732
|
let runtime = null;
|
|
726
733
|
try { runtime = readRuntime(ctx); } catch (error) {
|
|
727
734
|
if (pointerPresent && !recoverRuntimePointers()) {
|