Merge remote-tracking branch 'origin/main' into fix/empty-create-task
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # .task/feature-duplication-lesson-records.md
This commit is contained in:
@@ -11,3 +11,6 @@ runtime/
|
||||
|
||||
# ZCode CLI 会话生成的工具忽略文件(内容镜像 .gitignore,工具自动维护,不入库)
|
||||
.zcodeignore
|
||||
|
||||
# Mimosa 安全扫描插件的逐会话状态(hook-status/reports/ledger,机器自动重建)
|
||||
.mimosa/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# feature/exec-interpreters 任务卡
|
||||
|
||||
任务主记录:Backend https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Backend/pulls/33 ;Dev https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/113 ;状态:已完成(回填);owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-exec-interpreters(worktree);分支:feature/exec-interpreters
|
||||
- 授权与交付终点:落地 run_shell / run_python 并打开 Backend 与 Dev PR。合入 main 由所有者执行。不恢复 write_docx。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 目标:注册 run_shell / run_python。脚本落盘到会话沙箱 .agent/ 并保留;解释器限 bash / python3 绝对路径;超时与请求取消先到者生效,超时杀掉进程组;非零退出与超时以文本返回。
|
||||
- 附带:register_artifact 按扩展名写入 Office/PDF/图片 MIME,避免二进制被当成文本索引。
|
||||
- 非目标:写侧护栏与 indexTextOf(feature/binary-doc-index)、预览嗅探、输入排队。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 2026-10-01T03:58:48Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | d62f6806d2 | 2026-10-01T04:04:49Z |
|
||||
|
||||
## 结果与验证
|
||||
|
||||
- 结果:Backend feature/exec-interpreters @ 2880b58 注册两个执行器,并在 app.go 挂上。
|
||||
- 验证:Backend `go test ./...` 19 包 ok(含 echo 留痕、空脚本、runtime.exec 闸、进程组超时、python ZIP 魔数、register_artifact 回填)。Dev `make test` 通过:core、backend、frontend vitest 40、ui vitest 68、agent-command。
|
||||
- 影响与剩余项:模型可执行工作区脚本并登记二进制交付物。合入顺序为 Backend PR 然后 Dev PR。部署后的真人模型验收留到所有者合入之后。
|
||||
|
||||
## 闭合记录(card-autoclose 回填)
|
||||
|
||||
- 依据:merge 345d9db1e6486ec818c9b4f3c5139a903d4eee8b(PR #113)已包含于 origin/main,分支成果已落盘;本段为合入后回填。
|
||||
- 合并主题:Merge pull request 'Point backend at run_shell and run_python executors' (#113) from feature/exec-interpreters into main
|
||||
- 归档:随闭合移入 .task/archive/;任务执行期的过程证据见原任务记录与 PR。
|
||||
@@ -0,0 +1,29 @@
|
||||
# feature/binary-doc-index 任务卡
|
||||
|
||||
任务主记录:Backend https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Backend/pulls/34 ;Dev https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/114 ;状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-binary-doc-index(worktree);分支:feature/binary-doc-index
|
||||
- 授权与交付终点:重放 #99 里仍然有效的两项(写侧护栏、二进制工件抽文本再索引)。不恢复 format=docx。合入顺序在 run_shell/run_python(Dev #113)之后。合入由所有者执行。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 目标:write_artifact 与 fs_write_file 拒绝 .doc/.docx/.xls/.xlsx/.xlsm/.ppt/.pptx/.pdf,文案指向 run_python + register_artifact。二进制 mime 的工件经 ingest.Parse 抽出文本后才进索引。
|
||||
- 非目标:不带回 MarkdownToDocx 参数;不改上传路径的解析。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 2026-10-01T04:10:44Z |
|
||||
|
||||
## 结果与验证(完成后填写)
|
||||
|
||||
- 结果:Backend feature/binary-doc-index @ 3e5699c。Dev #99 与 Backend #27 已关闭并注明被 agent-native 路线取代。
|
||||
- 验证:go test ./... 19 包 ok(含 Office 扩展拒绝、docgen docx 可检索、坏 ZIP 不入库)。Dev `make test` 通过(2026-10-01,sync_base=4c4071e)。
|
||||
- 影响与剩余项:请在 Dev #113 合入后再合本 PR。
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 90a3a1d722a69d3637f45f1a8c387077aff8d9cf | 2026-10-01T04:12:41Z |
|
||||
| 同步前验收 | 4968f97b8531b90caa64534eae2a3bc8ec75bb5b | 46f89cf921fea1961b1176d1e3f288f7edcc0690 | 2026-10-01T05:25:41Z |
|
||||
| 同步前验收 | 22ecacf3f7d4ba3cb38f449056e74957fb75c016 | e7140825d8985535a37a30381e28bb0df85c6ce3 | 2026-10-01T05:27:47Z |
|
||||
@@ -52,6 +52,14 @@
|
||||
| 同步前验收 | 9f2a7fb4b806bb63f43c3ee759bdbb1ab1f97720 | 21a92441dce7787b8c3eaeaf731aad9a58215836 | 2026-09-30T16:49:57Z |
|
||||
| 同步前验收 | bb7f541d42dc6bd2609e59fed6760f22ed5c213e | dcb5bc0f727b5ceaf95b73b5ea514e63d9a89ae0 | 2026-09-30T17:17:46Z |
|
||||
| 同步前验收 | 978dc80817e7240f0a45a390ed2a6334041e84dd | 4eec51a954c1271729a3659544eb891f0181d8c2 | 2026-09-30T17:19:17Z |
|
||||
| 同步前验收 | d64742c71c1ebb8c1c88aef4c55194510f1cdf34 | 0b883469a2ad9f3b6b7cdb23c0ce0fb94d2d36b3 | 2026-09-30T17:51:59Z |
|
||||
| 同步前验收 | f65d89e59b6974c7a5db63be0677d192bfaa7e9c | 7ababf2a5420ab6047212ca86403314ee619fb99 | 2026-09-30T18:10:55Z |
|
||||
| 同步前验收 | 0be23f9a4d002a977de2998f687bc8555c3edb63 | 87cc6b3b555b65a2fc724bc310ff8fff10497fa3 | 2026-09-30T18:39:38Z |
|
||||
| 同步前验收 | 161fe684fc9ace176cae31a56a9337b2c0a70d59 | 29d24237f376fbf289b62c5e0df2c18679b90115 | 2026-09-30T19:19:50Z |
|
||||
| 同步前验收 | 3108a27be8195bffbf3f647a996a952dba73a142 | 6b78db5977508c819e29cddf66768c08fd93a97a | 2026-09-30T19:31:01Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | d62f6806d2ac19d8f069340c0dc8158e5f38983c | 2026-10-01T04:04:49Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | d179e27810f9338663ad1284af2b6c78597f11d8 | 2026-10-01T04:32:26Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 2192f946a405bc10b1cf829d107cb3cdbf7b8b55 | 2026-10-01T04:50:27Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | eb33d7b76ad9f0c9f62918b9c4ea24dab1534441 | 2026-10-01T04:59:18Z |
|
||||
| 同步前验收 | 76b2fb35a99e0847fff832b4e14e5766ea474c4e | 62d39037afafc98a6bbad3689cf479a299bc4ad8 | 2026-10-01T05:20:28Z |
|
||||
| 同步前验收 | 3072611209c445a0d87d54545cfd23d2b971e177 | 957de90142bc98bde3f479092e3892754000ef15 | 2026-10-01T05:23:44Z |
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# feature/input-queue 任务卡
|
||||
|
||||
任务主记录:[Dev #115](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/115)(Frontend [#28](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Frontend/pulls/28));状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-input-queue(worktree);分支:feature/input-queue
|
||||
- 授权与交付终点:纯前端。回合进行中可继续输入并进入本地队列;右栏增加文件页签,复用工件面板。不改后端串行。合入由所有者执行。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 目标:忙时「继续输入以排队」。队列可改、可删、可立即发送(忙则放到队首)。run 完成或失败后按序发送。HTTP 409 入队。右栏「文件」与 ⌘1 共用 ArtifactsPanel。
|
||||
- 非目标:后端消息队列、并发会话。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 2026-10-01T04:13:23Z |
|
||||
|
||||
## 结果与验证(完成后填写)
|
||||
|
||||
- 结果:Frontend feature/input-queue @ 3c81525。
|
||||
- 验证:npx tsc --noEmit 通过;vitest 42(含 outbox 两条)。
|
||||
- 影响与剩余项:切换会话会清空本地队列。
|
||||
@@ -0,0 +1,27 @@
|
||||
# feature/preview-sniff-fallback 任务卡
|
||||
|
||||
任务主记录:Dev PR #96 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/96(子仓:UI PR #21、Frontend PR #22);状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= d64742c71c1ebb8c1c88aef4c55194510f1cdf34
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-preview-sniff-fallback(worktree);分支:feature/preview-sniff-fallback
|
||||
- 授权与交付终点:用户已批准「研发智能体文档处理与自举方案评审会议纪要.docx 解析失败」整改方案中的渲染侧兜底轨道。允许:modules/ui、modules/frontend 代码与测试、父仓 .gitignore 与 gitlink 推进、推送分支并建 PR。终点=PR 建立;合入权在所有者(不自行代签合入)。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 根因:智能体经 write_artifact/fs_write_file 写出的 ".docx" 实为纯文本字节(生成侧无 OOXML 序列化),前端按扩展名派给 mammoth/JSZip 抛 "Can't find end of central directory"。本轨道只做渲染侧兜底,让存量坏文件可读、错误可解释。
|
||||
- 改动:① previewKindOf 将 `.doc`(老版二进制 Word,非 OOXML)归 binary,不再派给 mammoth;② OfficePreview 失败态文案收敛为用户可读提示(原始错误进 console);③ docxLoader 喂 mammoth 前嗅探 ZIP 魔数(PK\x03\x04),非 ZIP 按文本/markdown 回退渲染并提示;④ 父仓 .gitignore 收编 `.mimosa/`(Mimosa 插件逐会话状态目录反复弄脏树、阻塞 precheck)。
|
||||
- 非目标:不实现真正的 docx 生成;不动后端。xlsx/pptx 的 ZIP 嗅探已在本分支补上(2026-10-01);老版 .xls/.ppt 仍走原解析器。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | d64742c71c1ebb8c1c88aef4c55194510f1cdf34 | d64742c71c1ebb8c1c88aef4c55194510f1cdf34 | 2026-09-30T17:46:06Z |
|
||||
|
||||
## 结果与验证(完成后填写)
|
||||
|
||||
- 结果:UI e082889(含 origin/main 与 `.doc`→binary、Office 错误文案收敛);Frontend bfa634d(docx/xlsx/pptx 非 ZIP 按文本回退,.xls/.ppt 除外);父仓 .gitignore 含 `.mimosa/`。分支已并入 origin/main(a11fed4)。
|
||||
- 验证:合并后 UI vitest 68、Frontend vitest 40,两边 tsc 通过。Dev `make test` 通过(core、backend、frontend 40、ui 68、agent-command,2026-10-01)。
|
||||
- 影响与剩余项:伪 Office 文件预览可读。生成侧执行器在 feature/exec-interpreters,不在本 PR。合入顺序:UI #21 → Frontend #22 → Dev #96。
|
||||
@@ -0,0 +1,62 @@
|
||||
# feature/svc-remote-source 任务卡
|
||||
|
||||
任务主记录:Dev PR #102 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/102 ;状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= f65d89e59b6974c7a5db63be0677d192bfaa7e9c
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-svc-remote-source(worktree);分支:feature/svc-remote-source
|
||||
- 启动方式说明:主检出存在 owner 本人未收尾现场(`modules/frontend` 子模块修改态,前端重设计进行中),`task.sh start` 按门禁硬拒。owner 在任务对话中明确指示本任务并要求"更新/部署不依赖当前仓库状态",即 collaboration.md 的"经 owner 确认"路径;本工作区由 Agent 以与 task-start 完全相同的命令手动建立(同 R0、同命名、子模块零漂移),**全程未写主检出、未触碰该未提交现场**。
|
||||
- 授权与交付终点:修改 `scripts/svc.sh` 与 `docs/svc.md`(实现 + 文档),验证后推送并建 PR;不合并(合入由 owner 决定);不动主检出 `modules/frontend` 现场。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
**背景**:`scripts/svc.sh update dev` 在主检出工作树不干净时跳过更新("主检出工作树不干净——跳过")。owner 明确要求:更新、部署等操作不应依赖当前仓库状态;不指定时默认使用最新仓库;构建放在独立于当前仓库/目录的地方。
|
||||
|
||||
**目标**:
|
||||
1. 新增"独立部署源仓":脚本自有的干净克隆(默认 `~/.cache/agent-system-svc/src`,`SVC_SRC_DIR` 覆盖;可随时删除重建),dev 源的解析、列举(commits)、worktree 物化全部基于它。
|
||||
2. 默认来源改为远端最新:裸 `deploy` 与 `--from dev`(不带 @sha)= 源仓 `origin/main` 最新提交;`--from local` 保留为显式"构建当前工作区"。
|
||||
3. `update` 去 pull 化:删除"local 源 → 主检出 pull(要求分支=main + 树干净)"路径;`local@`/`dev@` 源一律重新部署为 `dev@<远端最新>`(隔离 worktree 构建),与工作区脏净/所在分支无关。领先/分叉/提交不在远端三种情形仍不动作(不盲目降级)。
|
||||
4. `update` 的 fetch 也走源仓(不再 fetch 主检出);`commits dev` 列表改为源仓 `origin/main`(自动确保+fetch),`[HEAD]` 标记改为 `[最新]`。
|
||||
5. 文档同步:脚本头注释、`help` 各主题、`docs/svc.md`(§2/§5/§6.3/§9.3/§11/§13/§14)。
|
||||
|
||||
**非目标**:不改 `--from local` 语义与实现;不改 release 源、数据库、生命周期、dbops 行为;不动 Makefile。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | f65d89e59b6974c7a5db63be0677d192bfaa7e9c | f65d89e59b6974c7a5db63be0677d192bfaa7e9c | 2026-09-30(手动 task-start 复刻) |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | (合并提交) | 2026-10-01T04:10:00Z |
|
||||
|
||||
## 结果与验证
|
||||
|
||||
- 结果:已实现(提交 a42fff6)。svc.sh 新增**独立部署源仓**(`SVC_SRC_DIR`,默认
|
||||
`~/.cache/agent-system-svc/src`,可随时删除重建):dev 源的提交解析、`commits` 列举、
|
||||
worktree 物化全部基于它;裸 `deploy` 与 `--from dev` 缺省取源仓 `origin/main` 最新;
|
||||
`update` 删除"主检出 pull(要求分支=main+树干净)"路径,`local@`/`dev@` 源一律重新
|
||||
部署为 `dev@<远端最新>`(领先/分叉/提交不在远端三种情形仍不动作);`docs/svc.md`
|
||||
与脚本 help 各主题同步更新。
|
||||
|
||||
- 验证:
|
||||
- `bash -n scripts/svc.sh` 通过;`help`/`help lifecycle` 渲染正常;
|
||||
- `scripts/svc.sh commits dev`:首次自动克隆源仓并 fetch,列表来自源仓 origin/main,
|
||||
顶提交标 `[最新]`;
|
||||
- 裸 `deploy --dry-run`(无 `--from`):计划 `dev@0be23f9`(源仓远端最新);
|
||||
- **端到端(复刻 owner 场景)**:在任务 worktree 制造脏现场(未跟踪文件 + 跟踪文件
|
||||
修改)并手工登记 `source=local@d64742c` 的服务,`scripts/svc.sh update svc-selftest`
|
||||
直接更新成功:`local@d64742c → 0be23f9`,从源仓物化隔离 worktree 构建(npm ci +
|
||||
vite + go build),服务启动健康(pid 1228696,http://127.0.0.1:8812,来源
|
||||
`dev@0be23f9`,版本组合完整),全程未触碰工作区;随后 stop + rm --purge 清理,
|
||||
worktree 无残留;
|
||||
- `make task-sync`:sync_base=0be23f9a4d,tested_head=87cc6b3b55(并入 PR #101 后组合);
|
||||
- `make test` 全绿(core ok;backend 全部 ok 含 server 4.8s;frontend 5 文件 33 用例;
|
||||
ui 7 文件 49 用例;agentcmd ok),退出码 0。
|
||||
|
||||
- 影响与剩余项:
|
||||
- 行为变化:部署缺省来源从"当前工作区"改为"远端 main 最新"——构建当前工作区须显式
|
||||
`--from local`;`update` 不再依赖主检出状态,owner 遇到的"工作树不干净——跳过"
|
||||
场景消除。
|
||||
- 观察项(非本任务引入):部署时对产物 `serve -h` 探测不到 `--auth` 会自动省略该
|
||||
flag(0be23f9 产物即如此),与旧版行为一致,健康检查通过。
|
||||
- 剩余项:PR 合入由 owner 决定;合入并在主检出 pull 后,旧版"树脏跳过"即消失。
|
||||
+49
-37
@@ -12,7 +12,8 @@ PostgreSQL 数据库(postgres)三类服务统一为"服务"模型——按
|
||||
- **登记持久化**:所有状态落盘(`svc.env` 当前态 + `history.jsonl` 事件流),`list` /
|
||||
`history` 全部从文件重建,脚本无内存状态、跨会话可追溯。
|
||||
- **不碰现场**:不改主检出 git 状态;只停"自己 pidfile + cmdline 双校验"通过的进程;
|
||||
端口冲突报错不抢;除 `--from local` 外的构建全部在隔离 worktree。
|
||||
端口冲突报错不抢;除 `--from local` 外的构建全部在隔离 worktree(物化自独立部署
|
||||
源仓,与当前工作区状态无关——脏树、任意分支均可部署/更新)。
|
||||
|
||||
分主题速查:`scripts/svc.sh help [model|deploy|lifecycle|db|dbops|config|examples|safety]`;
|
||||
本文档与 `--help` 内容同源,以实现为准。
|
||||
@@ -54,7 +55,8 @@ PostgreSQL 工具链定位顺序:`SVC_PG_BIN` 环境变量 → `pg_config --bi
|
||||
## 2. 90 秒上手
|
||||
|
||||
```bash
|
||||
# 一套演示后端(构建当前工作区 → 启动 → 健康检查)
|
||||
# 一套演示后端(缺省部署远端 main 最新:独立部署源仓物化构建 → 启动 → 健康检查;
|
||||
# 与当前工作区状态无关。要构建当前工作区:--from local)
|
||||
scripts/svc.sh dev deploy --mock
|
||||
|
||||
# 一个数据库 + 让后端连上它
|
||||
@@ -74,7 +76,7 @@ scripts/svc.sh db backup pg1 # pg_dump -Fc,自动自检
|
||||
scripts/svc.sh db restore pg1 --file <dump> --force # 覆盖恢复需 --force
|
||||
scripts/svc.sh db clone pg1 pg1test --port 8896 # 克隆一套到新端口
|
||||
|
||||
# 仓库更新后,一条命令把服务刷到最新
|
||||
# 把服务刷到远端最新(不依赖当前工作区状态:主检出脏树、任意分支均可)
|
||||
scripts/svc.sh update --check # 先看哪些服务落后
|
||||
scripts/svc.sh update # 自动更新过时且运行中的服务
|
||||
```
|
||||
@@ -215,9 +217,30 @@ scripts/svc.sh rm <name> --purge # 连 runtime/<name>/ 整个目录一起删
|
||||
|
||||
## 5. 命令参考:部署来源
|
||||
|
||||
`deploy --from` 支持三种来源(缺省 `local`),agent 与 static 共用:
|
||||
`deploy --from` 支持三种来源(**缺省 = `dev` 远端最新**),agent 与 static 共用:
|
||||
|
||||
### 5.1 local —— 当前工作区
|
||||
### 5.1 dev(缺省)—— 远端最新 / 指定提交
|
||||
|
||||
```
|
||||
scripts/svc.sh <name> deploy # 缺省 = dev 远端最新(origin/main)
|
||||
--from dev # 同缺省
|
||||
--from dev@<sha> # 指定提交(短/长 sha 均可)
|
||||
```
|
||||
|
||||
部署源来自**独立部署源仓**:脚本自有的干净克隆,默认 `~/.cache/agent-system-svc/src`
|
||||
(`SVC_SRC_DIR` 覆盖;首次使用自动从本仓 origin 克隆,可随时删除、下次自动重建)。
|
||||
dev 源的提交解析、`commits` 列举与构建 worktree 物化全部基于它——**更新与部署因此
|
||||
不依赖当前工作区状态**:主检出脏树、任意分支、甚至未 fetch 都不影响。
|
||||
|
||||
流程:源仓自动 fetch → `git worktree add --detach runtime/.worktrees/<sha> <sha>` →
|
||||
递归 `git submodule update --init --recursive`(子模块精确落位该提交的 gitlink 组合)→
|
||||
`make build`/`make frontend` → 产物复制 → worktree 回收。全程不触碰当前工作区。
|
||||
|
||||
- 可用提交列表:`scripts/svc.sh commits dev [N]`(列源仓 origin/main,自动确保+fetch);
|
||||
- 需要 npm/go 网络(构建在 worktree 内进行);
|
||||
- worktree 回收失败会提示手动命令,不阻塞部署结果。
|
||||
|
||||
### 5.2 local —— 当前工作区(显式)
|
||||
|
||||
```
|
||||
--from local
|
||||
@@ -225,23 +248,8 @@ scripts/svc.sh rm <name> --purge # 连 runtime/<name>/ 整个目录一起删
|
||||
|
||||
在主检出跑 `make build`(agent)或 `make frontend`(static),产物复制到服务目录。
|
||||
**这是唯一会写主检出的路径**,写的都是 gitignore 目录(`bin/`、`node_modules/`、
|
||||
`modules/frontend/dist/`),不产生任何 git 状态变化。适合"把我现在的工作区跑起来"。
|
||||
|
||||
### 5.2 dev@\<sha\> —— Dev 仓提交
|
||||
|
||||
```
|
||||
--from dev # 当前 HEAD
|
||||
--from dev@<sha> # 指定提交(短/长 sha 均可)
|
||||
```
|
||||
|
||||
流程:`git worktree add --detach runtime/.worktrees/<sha> <sha>` → 递归
|
||||
`git submodule update --init --recursive`(子模块精确落位该提交的 gitlink 组合)→
|
||||
`make build`/`make frontend` → 产物复制 → worktree 回收。全程不触碰当前工作区。
|
||||
|
||||
- 可用提交列表:`scripts/svc.sh commits dev [N]`;
|
||||
- 只列本地已有对象;远端新提交先 `git -C <仓库> fetch`;
|
||||
- 需要 npm/go 网络(构建在 worktree 内进行);
|
||||
- worktree 回收失败会提示手动命令,不阻塞部署结果。
|
||||
`modules/frontend/dist/`),不产生任何 git 状态变化;也是**唯一依赖当前工作区状态**
|
||||
的来源。适合"把我现在的工作区跑起来"。
|
||||
|
||||
### 5.3 release@\<版本\> —— Releases 仓制品
|
||||
|
||||
@@ -264,8 +272,8 @@ scripts/svc.sh <name> deploy --pick # 交互式编号选择
|
||||
scripts/svc.sh <name> deploy --dry-run # 只打印计划
|
||||
```
|
||||
|
||||
`commits` 表格:dev 源标注 `[HEAD]` 与 `[已部署:<服务名>]`(从各服务 `svc.env source=`
|
||||
汇总);release 源额外给出版本号与对应 Dev 提交。
|
||||
`commits` 表格:dev 源标注 `[最新]`(源仓 origin/main 顶)与 `[已部署:<服务名>]`
|
||||
(从各服务 `svc.env source=` 汇总);release 源额外给出版本号与对应 Dev 提交。
|
||||
|
||||
## 6. 命令参考:全局命令
|
||||
|
||||
@@ -303,7 +311,8 @@ scripts/svc.sh history [name] [N] # 默认全部服务、最近 20 条;首
|
||||
scripts/svc.sh update [name...] [--check] [--all] [--no-fetch]
|
||||
```
|
||||
|
||||
仓库更新后把服务刷到最新:fetch 远端 → 逐服务比较登记来源与最新 → 报告并(可选)更新。
|
||||
把服务刷到远端最新:fetch 独立部署源仓 → 逐服务比较登记来源与最新 → 报告并(可选)
|
||||
更新。**全程不依赖当前工作区状态**(主检出脏树、任意分支均可更新)。
|
||||
|
||||
| 用法 | 行为 |
|
||||
|---|---|
|
||||
@@ -317,7 +326,8 @@ scripts/svc.sh update [name...] [--check] [--all] [--no-fetch]
|
||||
|
||||
- `✓ 最新`——登记来源与最新一致,不动作;
|
||||
- `可更新`——本地来源是远端最新的祖先,将被更新;
|
||||
- `领先远端 main(不动作)` / `与远端 main 分叉(不自动更新)`——不盲目降级或强更;
|
||||
- `领先远端 main(不动作)` / `与远端 main 分叉(不自动更新)` /
|
||||
`提交不在远端(不自动更新)`——不盲目降级或强更;
|
||||
- `不适用`——postgres(无代码版本)与 static `--dir`(外部目录)不参与。
|
||||
|
||||
各来源的更新动作(复用 deploy 全链路:停旧 → 构建/校验 → 启动 → 健康检查;持久化配置
|
||||
@@ -325,8 +335,7 @@ scripts/svc.sh update [name...] [--check] [--all] [--no-fetch]
|
||||
|
||||
| 来源 | 更新方式 |
|
||||
|---|---|
|
||||
| `local@<sha>` | 当前分支为 main 且工作树干净时:自动 `git pull --ff-only origin main` + `make sync` + 重建;**树脏或非 main 分支则跳过并警告**(绝不碰未提交现场) |
|
||||
| `dev@<sha>` | `deploy --from dev@<远端 main 最新>`(隔离 worktree 构建,不碰主检出) |
|
||||
| `local@<sha>` / `dev@<sha>` | 一律 `deploy --from dev@<远端 main 最新>`(独立部署源仓 + 隔离 worktree 构建;不 pull 主检出、不看工作树状态) |
|
||||
| `release@<版本>` | `deploy --from release@<Releases 最新版本>`(sha256 校验) |
|
||||
|
||||
任一服务失败不中断其余服务;最终汇总 `成功/失败/跳过`。退出码:0 全部成功或最新;
|
||||
@@ -479,6 +488,7 @@ scripts/svc.sh prod deploy --env .env.prod # 等价
|
||||
|---|---|
|
||||
| `SVC_<NAME>_ADDR/DATA/DSN/AUTH/MOCK` | 按服务覆盖(NAME 大写、`-`→`_`,如 `staging` → `SVC_STAGING_ADDR`) |
|
||||
| `SVC_RELEASES_DIR` | Releases 仓路径(默认 `../Agent-System-Releases`) |
|
||||
| `SVC_SRC_DIR` | 独立部署源仓路径(默认 `~/.cache/agent-system-svc/src`) |
|
||||
| `SVC_PG_BIN` | PostgreSQL 工具链 bindir |
|
||||
| `SVC_MODEL_BASE/KEY/NAME` | 主模型(播种 `settings.models.chat`) |
|
||||
| `SVC_LIGHT_BASE/KEY/NAME` | 轻量模型 |
|
||||
@@ -531,9 +541,10 @@ scripts/svc.sh prod deploy --env .env.prod # 等价
|
||||
|
||||
## 11. 安全与边界
|
||||
|
||||
- **写入边界**:只写 `runtime/<name>/` 与 `runtime/.worktrees/`;不改主检出 git 状态;
|
||||
`--from local` 是唯一写主检出构建产物的路径(均 gitignore 目录);`rm --purge` 只删
|
||||
已登记服务的 `runtime/<name>/`。
|
||||
- **写入边界**:只写 `runtime/<name>/`、`runtime/.worktrees/` 与独立部署源仓
|
||||
(`SVC_SRC_DIR`,默认 `~/.cache/agent-system-svc/src`,可随时删除重建);不改主检出
|
||||
git 状态;`--from local` 是唯一写主检出构建产物的路径(均 gitignore 目录),也是
|
||||
唯一依赖当前工作区状态的来源;`rm --purge` 只删已登记服务的 `runtime/<name>/`。
|
||||
- **进程边界**:只停"pidfile + cmdline 标记"双校验通过的进程;postgres 走 `pg_ctl -m
|
||||
fast`,失败退 SIGTERM,SIGKILL 不用于 postmaster;agent/static TERM 10s 后才 KILL。
|
||||
- **端口边界**:被他人占用报错不抢;显式端口双重校验(登记 + 监听);派生端口避让。
|
||||
@@ -562,18 +573,19 @@ scripts/svc.sh prod deploy --env .env.prod # 等价
|
||||
| `pg_ctl start 失败` | 看 pg.log 常见:端口被占、pgdata 权限(须 700)、postmaster 残留 |
|
||||
| `pidfile 指向的进程已不存在` | 脚本自动清理 pidfile;直接重新 start 即可 |
|
||||
| `sha256 校验失败` | 制品与 manifest 不符:不要部署;在 Releases 仓重新 build |
|
||||
| `Dev 仓无此提交` | 本地无该对象:`git -C <仓库> fetch` 后重试 |
|
||||
| `worktree 回收失败` | 按提示手动 `git worktree remove --force runtime/.worktrees/<sha>` |
|
||||
| `子模块物化失败` | 子模块对象缺失:先 fetch;或网络问题重试 |
|
||||
| `部署源仓无此提交` | 源仓已自动 fetch 仍无此对象:确认 sha 正确(`scripts/svc.sh commits dev`) |
|
||||
| `worktree 回收失败` | 按提示手动 `git -C <部署源仓> worktree remove --force runtime/.worktrees/<sha>` |
|
||||
| `子模块物化失败` | 网络或子模块对象问题:重试(部署源仓会自动 fetch);或检查 git 远端可达性 |
|
||||
| `目标库已有 N 张表——拒绝覆盖` | 确认后加 `--force`(会 drop 重建) |
|
||||
| `update 报"当前分支非 main"或"工作树不干净" | local 源服务的自动 pull 被防护跳过:先自行收尾/pull,再重跑 update;或改用 `deploy --from dev@<sha>` |
|
||||
| `提交不在远端(不自动更新)` | 该服务部署自未推送的本地提交(如 `--from local`):重新 `deploy`(缺省即远端最新)即可纳入更新轨道 |
|
||||
| `list 里服务显示未运行但进程在` | 手工起的进程不满足 pidcheck 标记:脚本不会动它;纳入管理请走 svc 部署 |
|
||||
|
||||
## 14. 配方索引
|
||||
|
||||
```bash
|
||||
# ① 演示后端
|
||||
# ① 演示后端(缺省部署远端 main 最新;--from local 构建当前工作区)
|
||||
scripts/svc.sh dev deploy --mock
|
||||
scripts/svc.sh dev deploy --from local --mock
|
||||
|
||||
# ② 建库 + 后端连库
|
||||
scripts/svc.sh db create pg1 --port 8890
|
||||
@@ -608,7 +620,7 @@ scripts/svc.sh db copy pgdev pgprod --db app --force
|
||||
# ⑨ 换端口
|
||||
scripts/svc.sh set pg1 --port 8895 --apply
|
||||
|
||||
# ⑩ 仓库更新后刷新服务
|
||||
# ⑩ 把服务刷到远端最新(主检出脏树/任意分支均可)
|
||||
scripts/svc.sh update --check # 看哪些落后
|
||||
scripts/svc.sh update # 更新过时且运行中的(数据与配置保留)
|
||||
scripts/svc.sh update dev # 只刷新指定服务
|
||||
|
||||
+1
-1
Submodule modules/backend updated: 3c08f9008e...42fe6196b1
+1
-1
Submodule modules/ui updated: d271a9d3c0...e082889200
+106
-87
@@ -19,13 +19,15 @@
|
||||
# scripts/svc.sh db set <name> [...] 等价于 set
|
||||
# scripts/svc.sh commits [dev|release] [N] 可部署提交列表(默认 dev,N=20)
|
||||
# scripts/svc.sh history [name] [N] 事件历史(默认全部,最近 20 条)
|
||||
# scripts/svc.sh update [name] [--check] [--all] 检测远端最新并更新过时服务
|
||||
# scripts/svc.sh update [name] [--check] [--all] 检测远端最新并更新过时服务(与当前工作区状态无关)
|
||||
# scripts/svc.sh help [主题] 分主题详细帮助
|
||||
#
|
||||
# ════════════════════ 部署来源(agent/static 的 deploy)════════════════════
|
||||
# (缺省)dev@远端最新 不指定 --from 时默认部署源仓 origin/main 最新提交——
|
||||
# 更新/部署不依赖当前工作区状态(脏树、任意分支均可)
|
||||
# --from dev[@<sha>] 同缺省;@<sha> 显式指定提交。物化与构建在独立部署源仓的
|
||||
# 隔离 worktree(runtime/.worktrees/<sha>)进行,不触碰当前工作区
|
||||
# --from local 构建当前工作区(唯一写主检出构建产物的路径,均 gitignore)
|
||||
# --from dev[@<sha>] 隔离 worktree(runtime/.worktrees/<sha>)物化该提交的
|
||||
# 子模块组合并构建,不触碰当前工作区
|
||||
# --from release[@<版本|sha>] Releases 仓制品(sha256 对 versions/<v>/manifest.json 校验)
|
||||
# --pick [dev|release] 交互式编号选提交;--dry-run 只打印部署计划
|
||||
#
|
||||
@@ -73,9 +75,10 @@
|
||||
# make svc ENV=dev ARGS="--env .env.dev --port 9000"
|
||||
#
|
||||
# ════════════════════ 安全约束 ════════════════════
|
||||
# - 只写 runtime/<name>/ 与 runtime/.worktrees/;不改主检出 git 状态、不动他人现场;
|
||||
# - 只写 runtime/<name>/、runtime/.worktrees/ 与独立部署源仓(SVC_SRC_DIR,默认
|
||||
# ~/.cache/agent-system-svc/src,可随时删除重建);不改主检出 git 状态、不动他人现场;
|
||||
# --from local 是唯一写主检出构建产物(bin/、node_modules/、dist/,均 gitignore)
|
||||
# 的路径,dev@sha/release/static 构建全部在隔离 worktree;
|
||||
# 的路径,dev@sha/release/static 构建全部在隔离 worktree(自部署源仓物化);
|
||||
# - 只停自己启动的进程:pidfile + /proc/<pid>/cmdline 标记双校验;postgres 走
|
||||
# pg_ctl -m fast 优雅停机,SIGKILL 不用于 postmaster;
|
||||
# - 端口被非本脚本进程占用时报错并给出占用者,不抢不杀;
|
||||
@@ -92,6 +95,10 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
RUNTIME="$ROOT/runtime"
|
||||
BIN="$ROOT/bin/agent-system"
|
||||
SVC_ENVFILE=""
|
||||
# 独立部署源仓:脚本自有的干净克隆(默认 ~/.cache/agent-system-svc/src,SVC_SRC_DIR 覆盖)。
|
||||
# dev 源的解析/列举/worktree 物化全部基于它——更新与部署因此不依赖当前工作区状态
|
||||
# (脏树、任意分支均可);目录可随时删除,下次使用自动重建。
|
||||
SRC_DIR="${SVC_SRC_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/agent-system-svc/src}"
|
||||
|
||||
# 提示信息走 stderr:stdout 只留给数据(提交表/服务表/DSN),便于 $( ) 捕获组合。
|
||||
c_info() { printf '\033[1;34m[svc]\033[0m %s\n' "$*" >&2; }
|
||||
@@ -110,7 +117,7 @@ svc.sh —— 本机服务管理:后端(agent) / 前端(static) / 数据库(po
|
||||
|
||||
常用:
|
||||
scripts/svc.sh list [--tag T] 服务总览
|
||||
scripts/svc.sh <name> deploy --from dev@<sha> 按提交部署并启动(agent/static)
|
||||
scripts/svc.sh <name> deploy [--from dev@<sha>] 部署并启动(缺省=远端 main 最新)
|
||||
scripts/svc.sh <name> start|stop|restart|logs [N] 生命周期与日志
|
||||
scripts/svc.sh <name> status 服务详情(版本/来源/DSN 等)
|
||||
scripts/svc.sh db create pg1 --port 8890 建数据库
|
||||
@@ -119,7 +126,7 @@ svc.sh —— 本机服务管理:后端(agent) / 前端(static) / 数据库(po
|
||||
scripts/svc.sh rm pg1 [--purge] 注销(--purge 连数据删除)
|
||||
scripts/svc.sh commits [dev|release] [N] 可部署提交
|
||||
scripts/svc.sh history [name] [N] 事件历史
|
||||
scripts/svc.sh update [name] [--check] 检测远端最新并更新过时服务
|
||||
scripts/svc.sh update [name] [--check] 刷新过时服务到远端最新(不依赖工作区状态)
|
||||
|
||||
帮助:--help 完整帮助 | help [主题] 分主题(model deploy lifecycle db dbops config examples safety)
|
||||
文档:docs/svc.md
|
||||
@@ -204,13 +211,18 @@ EOF
|
||||
|
||||
语法:scripts/svc.sh <name> deploy [--kind agent|static] [--from 源] [参数...]
|
||||
|
||||
部署来源(--from,默认 local):
|
||||
部署来源(--from,缺省=dev 远端最新):
|
||||
(缺省)/ dev 部署独立部署源仓的 origin/main 最新提交——与当前工作区
|
||||
状态无关(脏树、任意分支均可)。
|
||||
dev@<sha> 显式指定提交,物化与构建同上。
|
||||
两者统一流程:在独立部署源仓(SVC_SRC_DIR,默认 ~/.cache/agent-system-svc/src,
|
||||
首次使用自动从 origin 克隆)上 git worktree add --detach 出
|
||||
runtime/.worktrees/<sha>,递归物化子模块组合(精确落位 gitlink),
|
||||
make build/frontend,产物复制后回收 worktree。全程不触碰当前工作区。
|
||||
local 构建当前工作区(make build / make frontend),产物复制到
|
||||
服务目录。注意:这是唯一会写主检出构建产物(bin/、
|
||||
node_modules/、dist/——均 gitignore)的路径。
|
||||
dev[@<sha>] 在隔离 worktree(runtime/.worktrees/<sha>)检出该提交,
|
||||
递归物化子模块组合(精确落位 gitlink),make build/frontend,
|
||||
产物复制后回收 worktree。子模块对象缺失时需先 git fetch。
|
||||
node_modules/、dist/——均 gitignore)的路径,也是唯一
|
||||
依赖当前工作区状态的来源。
|
||||
release[@<版本|sha>] 取 Releases 仓 build/<v>/agent-system(+plugins),
|
||||
sha256 对 versions/<v>/manifest.json 校验,不符即拒绝。
|
||||
--pick [dev|release] 交互式编号选择(需 TTY;列表与提示走 stderr)
|
||||
@@ -255,14 +267,14 @@ EOF
|
||||
scripts/svc.sh rm <name> 停止并移除登记(目录/数据/历史保留)
|
||||
scripts/svc.sh rm <name> --purge 连 runtime/<name>/ 整个目录一起删除
|
||||
|
||||
自动更新(仓库更新后一条命令刷新服务):
|
||||
自动更新(一条命令把服务刷到远端最新;与当前工作区状态无关):
|
||||
scripts/svc.sh update --check 只报告:每服务 当前来源 vs 最新(fetch 后比较)
|
||||
scripts/svc.sh update 更新所有"过时且运行中"的服务
|
||||
scripts/svc.sh update dev prod 点名更新(已停止的过时服务也会更新并启动)
|
||||
scripts/svc.sh update --all 含已停止服务;--no-fetch 跳过网络
|
||||
- local 源:自动 git pull --ff-only origin main + make sync 后重建
|
||||
(仅当前分支==main 且工作树干净;否则跳过并警告,不碰未提交现场)
|
||||
- dev@sha 源:直接部署远端 main 最新提交(隔离 worktree 构建,不碰主检出)
|
||||
- local@/dev@ 源:一律重新部署为 dev@<远端 main 最新>(独立部署源仓 + 隔离
|
||||
worktree 构建;主检出脏净、所在分支均不影响,也不 pull 主检出)
|
||||
- 领先远端 main / 与远端分叉 / 提交不在远端:报告但不动作(不盲目降级)
|
||||
- release@源:部署 Releases 仓最新版本(sha256 校验)
|
||||
- postgres / static --dir 不参与更新;每次更新写 history(update 事件)
|
||||
EOF
|
||||
@@ -345,6 +357,7 @@ dotenv 格式:KEY=VALUE,支持 # 注释、成对引号、export 前缀;只
|
||||
环境变量(X 为服务名大写,- → _):
|
||||
SVC_X_ADDR / SVC_X_DATA / SVC_X_DSN / SVC_X_AUTH / SVC_X_MOCK
|
||||
SVC_RELEASES_DIR Releases 仓路径(默认 ../Agent-System-Releases)
|
||||
SVC_SRC_DIR 独立部署源仓路径(默认 ~/.cache/agent-system-svc/src)
|
||||
SVC_PG_BIN postgres 工具链 bindir(默认 pg_config --bindir 探测)
|
||||
SVC_MODEL_BASE/KEY/NAME 主模型(agent 启动健康后播种)
|
||||
SVC_LIGHT_BASE/KEY/NAME 轻量模型
|
||||
@@ -362,8 +375,9 @@ EOF
|
||||
cat >&2 <<'EOF'
|
||||
【examples】常见配方
|
||||
|
||||
① 起一套演示后端(当前工作区构建):
|
||||
① 起一套演示后端(缺省部署远端 main 最新;--from local 才构建当前工作区):
|
||||
scripts/svc.sh dev deploy --mock
|
||||
scripts/svc.sh dev deploy --from local --mock
|
||||
② 建库 + 后端连库:
|
||||
scripts/svc.sh db create pg1 --port 8890
|
||||
scripts/svc.sh pg1 start
|
||||
@@ -401,9 +415,10 @@ EOF
|
||||
【safety】安全约束与边界
|
||||
|
||||
写入边界:
|
||||
- 只写 runtime/<name>/ 与 runtime/.worktrees/(构建 worktree,用后即收);
|
||||
- 只写 runtime/<name>/、runtime/.worktrees/(构建 worktree,用后即收)与独立
|
||||
部署源仓(SVC_SRC_DIR,默认 ~/.cache/agent-system-svc/src,可随时删除重建);
|
||||
- 不改主检出 git 状态;--from local 是唯一写主检出构建产物(bin/、node_modules/、
|
||||
dist/——均 gitignore)的路径;
|
||||
dist/——均 gitignore)的路径,也是唯一依赖当前工作区状态的来源;
|
||||
- rm --purge 只删 runtime/<name>/,且要求服务已登记。
|
||||
|
||||
进程边界:
|
||||
@@ -781,6 +796,31 @@ releases_root() {
|
||||
fi
|
||||
}
|
||||
|
||||
# svc_src_ready:确保独立部署源仓就绪(不存在则从 $ROOT 的 origin 首次克隆)并 fetch
|
||||
# 远端;--no-fetch 跳过网络。同一次命令运行内幂等(首个调用定下 fetch 策略)。
|
||||
# 失败 return 1(无 origin 可克隆/克隆失败),调用方自行决定报错或降级。
|
||||
SRC_READY_DONE=0
|
||||
svc_src_ready() {
|
||||
[ "$SRC_READY_DONE" = 1 ] && return 0
|
||||
if [ ! -d "$SRC_DIR/.git" ]; then
|
||||
local url
|
||||
url="$(git -C "$ROOT" remote get-url origin 2>/dev/null || true)"
|
||||
[ -n "$url" ] || { c_err "无法确定 origin 地址($ROOT 无 origin 远端);可用 SVC_SRC_DIR 指向已有仓"; return 1; }
|
||||
c_info "初始化独立部署源仓:$SRC_DIR(← origin;与当前工作区无关,可随时删除重建)"
|
||||
mkdir -p "$(dirname "$SRC_DIR")"
|
||||
if ! git clone --quiet "$url" "$SRC_DIR" >&2; then
|
||||
c_err "部署源仓克隆失败:$url → $SRC_DIR"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [ "${1:-}" != "--no-fetch" ]; then
|
||||
c_info "git fetch(独立部署源仓:$SRC_DIR)"
|
||||
git -C "$SRC_DIR" fetch origin --quiet 2>/dev/null || c_warn "部署源仓 fetch 失败——基于本地缓存($SRC_DIR)"
|
||||
fi
|
||||
SRC_READY_DONE=1
|
||||
return 0
|
||||
}
|
||||
|
||||
deployed_envs() {
|
||||
local key="$1" d e s out=""
|
||||
for d in "$RUNTIME"/*/; do
|
||||
@@ -797,20 +837,21 @@ print_commit_list() { # SRC N PICK:提交表到 stdout;PICK=1 时填充 PICK
|
||||
local src="$1" count="$2" pick="$3"
|
||||
local sep=$'\037'
|
||||
if [ "$src" = dev ]; then
|
||||
c_info "Dev 仓提交($ROOT;倒序取 $count 条)——部署:scripts/svc.sh <name> deploy --from dev@<sha>"
|
||||
svc_src_ready || { c_err "部署源仓不可用,无法列出可部署提交"; return 1; }
|
||||
c_info "Dev 仓提交(独立部署源仓 $SRC_DIR 的 origin/main;倒序取 $count 条)——部署:scripts/svc.sh <name> deploy --from dev@<sha>"
|
||||
printf ' %3s %-9s %-10s %s\n' '#' 'sha' '日期' '主题'
|
||||
local head_short; head_short="$(git -C "$ROOT" rev-parse --short HEAD)"
|
||||
local latest_short; latest_short="$(git -C "$SRC_DIR" rev-parse --short origin/main 2>/dev/null || true)"
|
||||
local n=0 h date subject marks envs
|
||||
while IFS="$sep" read -r h date subject; do
|
||||
[ -z "$h" ] && continue
|
||||
n=$((n + 1))
|
||||
marks=""
|
||||
[ "$h" = "$head_short" ] && marks="${marks}[HEAD]"
|
||||
[ "$h" = "$latest_short" ] && marks="${marks}[最新]"
|
||||
envs="$(deployed_envs "dev@$h")"
|
||||
[ -n "$envs" ] && marks="${marks}[已部署:$envs]"
|
||||
printf ' %3d %-9s %-10s %s %s\n' "$n" "$h" "$date" "$subject" "$marks"
|
||||
[ "$pick" = 1 ] && PICK_OPTS+=("$h")
|
||||
done < <(git -C "$ROOT" log -n "$count" --format="%h${sep}%ad${sep}%s" --date=short)
|
||||
done < <(git -C "$SRC_DIR" log -n "$count" --format="%h${sep}%ad${sep}%s" --date=short origin/main)
|
||||
else
|
||||
c_info "Releases 仓提交($REL_ROOT;倒序取 $count 条)——部署:scripts/svc.sh <name> deploy --from release@<版本>"
|
||||
printf ' %3s %-9s %-10s %-8s %-9s %s\n' '#' 'sha' '日期' '版本' 'dev提交' '主题'
|
||||
@@ -882,7 +923,7 @@ resolve_release() { # REF(空=最新) → REL_COMMIT/REL_VERSION/SRC_DEVCOMMIT
|
||||
}
|
||||
|
||||
resolve_source() { # → SRC_KINDSRC(local|dev|release) + SRC_LABEL(+SRC_FULL/SRC_SHA/REL_*)
|
||||
local spec="${CLI_FROM:-local}"
|
||||
local spec="${CLI_FROM:-dev}"
|
||||
if [ -n "$CLI_PICK" ]; then
|
||||
[ "$CLI_PICK" = release ] && releases_root
|
||||
spec="$(pick_commit "$CLI_PICK")"
|
||||
@@ -893,16 +934,18 @@ resolve_source() { # → SRC_KINDSRC(local|dev|release) + SRC_LABEL(+SRC_FULL/
|
||||
SRC_LABEL="local@$(git -C "$ROOT" rev-parse --short HEAD)"
|
||||
;;
|
||||
dev|dev@*)
|
||||
local ref="HEAD"
|
||||
# 缺省 ref=origin/main(独立部署源仓的远端最新);显式 @<sha> 亦可。
|
||||
local ref="origin/main"
|
||||
case "$spec" in dev@*) ref="${spec#dev@}" ;; esac
|
||||
svc_src_ready || { c_err "部署源仓不可用——dev 源依赖它;或改用 --from local 构建当前工作区"; exit 2; }
|
||||
local full
|
||||
full="$(git -C "$ROOT" rev-parse --verify --quiet "${ref}^{commit}")" || {
|
||||
c_err "Dev 仓无此提交:$ref(若是远端新提交,先 git -C $ROOT fetch;可用项:scripts/svc.sh commits dev)"
|
||||
full="$(git -C "$SRC_DIR" rev-parse --verify --quiet "${ref}^{commit}")" || {
|
||||
c_err "部署源仓无此提交:$ref(已自动 fetch;可用项:scripts/svc.sh commits dev)"
|
||||
exit 2
|
||||
}
|
||||
SRC_KINDSRC=dev
|
||||
SRC_FULL="$full"
|
||||
SRC_SHA="$(git -C "$ROOT" rev-parse --short "$full")"
|
||||
SRC_SHA="$(git -C "$SRC_DIR" rev-parse --short "$full")"
|
||||
SRC_LABEL="dev@$SRC_SHA"
|
||||
;;
|
||||
release|release@*)
|
||||
@@ -942,13 +985,13 @@ materialize_dev_commit() {
|
||||
if [ -d "$wt" ]; then
|
||||
c_info "[$ENV_NAME] 复用已有构建 worktree:$wt"
|
||||
else
|
||||
c_info "[$ENV_NAME] 物化 Dev 提交 $sha → 隔离 worktree(不触碰当前工作区)"
|
||||
git -C "$ROOT" worktree add --detach "$wt" "$full" >/dev/null || return 1
|
||||
c_info "[$ENV_NAME] 物化 Dev 提交 $sha → 隔离 worktree(源:独立部署源仓 $SRC_DIR,不触碰当前工作区)"
|
||||
git -C "$SRC_DIR" worktree add --detach "$wt" "$full" >/dev/null || return 1
|
||||
fi
|
||||
c_info "[$ENV_NAME] 物化子模块组合(git submodule update --init --recursive;缺对象时需网络)"
|
||||
# stdout 只留给最后的 worktree 路径(调用方 $() 捕获)——子模块/构建输出全部走 stderr。
|
||||
git -C "$wt" submodule update --init --recursive >&2 || {
|
||||
c_err "[$ENV_NAME] 子模块物化失败(对象缺失时先 git -C $ROOT fetch origin)"
|
||||
c_err "[$ENV_NAME] 子模块物化失败(网络或对象缺失;重试会自动 fetch 部署源仓)"
|
||||
return 1
|
||||
}
|
||||
c_info "[$ENV_NAME] 构建(make $target:npm ci + 构建,需网络)"
|
||||
@@ -960,8 +1003,8 @@ materialize_dev_commit() {
|
||||
recycle_worktree() {
|
||||
local wt="$RUNTIME/.worktrees/$1"
|
||||
c_info "[$ENV_NAME] 回收构建 worktree"
|
||||
git -C "$ROOT" worktree remove --force "$wt" >/dev/null 2>&1 \
|
||||
|| c_warn "[$ENV_NAME] worktree 回收失败,可手动:git -C $ROOT worktree remove --force $wt"
|
||||
git -C "$SRC_DIR" worktree remove --force "$wt" >/dev/null 2>&1 \
|
||||
|| c_warn "[$ENV_NAME] worktree 回收失败,可手动:git -C $SRC_DIR worktree remove --force $wt"
|
||||
}
|
||||
|
||||
materialize_release() {
|
||||
@@ -1027,7 +1070,7 @@ print_agent_plan() {
|
||||
printf ' 来源:%s(make build 当前工作区;唯一写主检出构建产物的路径)\n' "$SRC_LABEL"
|
||||
printf ' 产物:%s ← %s + %s/plugins\n' "$ENV_BIN" "$BIN" "$ROOT" ;;
|
||||
dev)
|
||||
printf ' 来源:%s(完整提交 %s)\n' "$SRC_LABEL" "$SRC_FULL"
|
||||
printf ' 来源:%s(完整提交 %s;独立部署源仓 %s)\n' "$SRC_LABEL" "$SRC_FULL" "$SRC_DIR"
|
||||
printf ' 物化:worktree %s(submodule update --init --recursive + make build)\n' "$RUNTIME/.worktrees/$SRC_SHA" ;;
|
||||
release)
|
||||
printf ' 来源:%s(Releases 提交 %s)\n' "$SRC_LABEL" "$(git -C "$REL_ROOT" rev-parse --short "$REL_COMMIT")"
|
||||
@@ -1229,8 +1272,8 @@ print_static_plan() {
|
||||
else
|
||||
case "$SRC_KINDSRC" in
|
||||
local) printf ' 来源:%s(make frontend → htdocs/)\n' "$SRC_LABEL" ;;
|
||||
dev) printf ' 来源:%s(完整提交 %s)\n 物化:worktree %s(make frontend → htdocs/)\n' \
|
||||
"$SRC_LABEL" "$SRC_FULL" "$RUNTIME/.worktrees/$SRC_SHA" ;;
|
||||
dev) printf ' 来源:%s(完整提交 %s;独立部署源仓 %s)\n 物化:worktree %s(make frontend → htdocs/)\n' \
|
||||
"$SRC_LABEL" "$SRC_FULL" "$SRC_DIR" "$RUNTIME/.worktrees/$SRC_SHA" ;;
|
||||
release) printf ' 来源:release —— 不支持(制品内嵌前端);请用 dev|local 或 --dir\n' ;;
|
||||
esac
|
||||
fi
|
||||
@@ -2047,9 +2090,10 @@ cmd_history() {
|
||||
# ---- 自动检索与更新 ----
|
||||
|
||||
# cmd_update [NAME...] [--check] [--all] [--no-fetch]:
|
||||
# fetch 远端 → 逐服务比较登记 source 与最新(Dev 仓 origin/main / Releases 最新版本)→
|
||||
# fetch 独立部署源仓 → 逐服务比较登记 source 与远端 main 最新(Releases 最新版本)→
|
||||
# --check 只报告;否则更新"过时且运行中"的服务(点名或 --all 时含已停止)。
|
||||
# local 源的自动 pull 受三重保护:当前分支==main + 工作树干净 + --ff-only。
|
||||
# local@/dev@ 源一律重新部署为 dev@<远端最新>(隔离 worktree 构建)——与主检出
|
||||
# 工作树状态完全无关(脏树、任意分支均可);领先/分叉/提交不在远端不动作。
|
||||
cmd_update() {
|
||||
local names=() a
|
||||
while [ $# -gt 0 ]; do
|
||||
@@ -2081,28 +2125,21 @@ cmd_update() {
|
||||
fi
|
||||
[ "${#targets[@]}" -gt 0 ] || { c_info "暂无已登记服务(db create / deploy 会登记)"; return 0; }
|
||||
|
||||
# fetch 远端(一次性;失败不致命,退化为本地缓存引用比较)。
|
||||
local fetch_note=""
|
||||
if [ "$CLI_NOFETCH" = 1 ]; then
|
||||
fetch_note="基于本地缓存引用"
|
||||
else
|
||||
c_info "git fetch origin(检索远端更新)"
|
||||
if git -C "$ROOT" fetch origin --quiet 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
fetch_note="fetch 失败,基于本地缓存引用"
|
||||
c_warn "git fetch 失败——$fetch_note"
|
||||
fi
|
||||
fi
|
||||
local latest_sha
|
||||
latest_sha="$(git -C "$ROOT" rev-parse --verify --quiet origin/main || true)"
|
||||
|
||||
# Releases 最新版本(仅当存在 release 源服务时才访问 Releases 仓)。
|
||||
local latest_rel="" need_rel=0 e_src
|
||||
# 按目标来源决定访问哪些仓:local@/dev@ 走独立部署源仓;release@ 走 Releases 仓。
|
||||
local latest_sha="" latest_rel="" need_rel=0 need_dev=0 e_src
|
||||
for e in ${targets[@]+"${targets[@]}"}; do
|
||||
e_src="$(sed -n 's/^source=//p' "$RUNTIME/$e/svc.env" | head -1)"
|
||||
case "$e_src" in release@*) need_rel=1 ;; esac
|
||||
case "$e_src" in release@*) need_rel=1 ;; local@*|dev@*) need_dev=1 ;; esac
|
||||
done
|
||||
local fetch_note="" src_args=""
|
||||
[ "$CLI_NOFETCH" = 1 ] && { fetch_note="--no-fetch,基于本地缓存引用"; src_args="--no-fetch"; }
|
||||
if [ "$need_dev" = 1 ]; then
|
||||
if svc_src_ready $src_args; then
|
||||
latest_sha="$(git -C "$SRC_DIR" rev-parse --verify --quiet origin/main || true)"
|
||||
else
|
||||
c_warn "部署源仓不可用——local/dev 源服务本轮无法检测与更新"
|
||||
fi
|
||||
fi
|
||||
if [ "$need_rel" = 1 ]; then
|
||||
releases_root
|
||||
if [ "$CLI_NOFETCH" != 1 ]; then
|
||||
@@ -2138,14 +2175,17 @@ cmd_update() {
|
||||
cur="${src##*@}"
|
||||
if [ -z "$latest_sha" ]; then
|
||||
state="远端 main 未知"; latest_disp="-"
|
||||
elif ! git -C "$SRC_DIR" cat-file -e "${cur}^{commit}" 2>/dev/null; then
|
||||
state="提交不在远端(不自动更新;重新 deploy 可纳入更新轨道)"
|
||||
latest_disp="$(git -C "$SRC_DIR" rev-parse --short "$latest_sha" 2>/dev/null || echo "-")"
|
||||
elif [ "${latest_sha:0:${#cur}}" = "$cur" ]; then
|
||||
state="✓ 最新"; latest_disp="$(git -C "$ROOT" rev-parse --short "$latest_sha" 2>/dev/null || echo "-")"
|
||||
elif git -C "$ROOT" merge-base --is-ancestor "$cur" "$latest_sha" 2>/dev/null; then
|
||||
to="$(git -C "$ROOT" rev-parse --short "$latest_sha" 2>/dev/null || true)"
|
||||
state="✓ 最新"; latest_disp="$(git -C "$SRC_DIR" rev-parse --short "$latest_sha" 2>/dev/null || echo "-")"
|
||||
elif git -C "$SRC_DIR" merge-base --is-ancestor "$cur" "$latest_sha" 2>/dev/null; then
|
||||
to="$(git -C "$SRC_DIR" rev-parse --short "$latest_sha" 2>/dev/null || true)"
|
||||
latest_disp="$to"
|
||||
state="可更新"
|
||||
elif git -C "$ROOT" merge-base --is-ancestor "$latest_sha" "$cur" 2>/dev/null; then
|
||||
state="领先远端 main(不动作)"; latest_disp="$(git -C "$ROOT" rev-parse --short "$latest_sha" 2>/dev/null || echo "-")"
|
||||
elif git -C "$SRC_DIR" merge-base --is-ancestor "$latest_sha" "$cur" 2>/dev/null; then
|
||||
state="领先远端 main(不动作)"; latest_disp="$(git -C "$SRC_DIR" rev-parse --short "$latest_sha" 2>/dev/null || echo "-")"
|
||||
else
|
||||
state="与远端 main 分叉(不自动更新)"; latest_disp="-"
|
||||
fi
|
||||
@@ -2195,32 +2235,11 @@ cmd_update() {
|
||||
local from="${rest%%|*}" tov="${rest#*|}"
|
||||
local deploy_from=""
|
||||
env_config "$name"
|
||||
# local@/dev@ 源统一重新部署为 dev@<远端最新>:独立部署源仓 + 隔离 worktree 构建,
|
||||
# 不 pull 主检出、不看工作树状态(脏树、任意分支均可更新)。
|
||||
case "$from" in
|
||||
local@*)
|
||||
local branch dirty
|
||||
branch="$(git -C "$ROOT" rev-parse --abbrev-ref HEAD)"
|
||||
if [ "$branch" != "main" ]; then
|
||||
c_warn "[$name] 当前分支 $branch 非 main——跳过自动 pull(手动更新后重跑 update)"
|
||||
skipped=$((skipped + 1)); continue
|
||||
fi
|
||||
dirty="$(git -C "$ROOT" status --porcelain | grep -v '^.. \.zcode/' || true)"
|
||||
if [ -n "$dirty" ]; then
|
||||
c_warn "[$name] 主检出工作树不干净——跳过(不碰未提交现场)"
|
||||
skipped=$((skipped + 1)); continue
|
||||
fi
|
||||
c_info "[$name] git pull --ff-only origin main + make sync"
|
||||
if ! git -C "$ROOT" pull --ff-only origin main >/dev/null 2>&1; then
|
||||
c_err "[$name] 自动 pull 失败(可能本地 main 与远端分叉)——跳过,请手动处理"
|
||||
hist_event update fail "$(read_pid)" "pull 失败(from=$from)"
|
||||
failed=$((failed + 1)); continue
|
||||
fi
|
||||
if ! make -C "$ROOT" sync >/dev/null 2>&1; then
|
||||
c_warn "[$name] make sync 失败——继续构建(若子模块缺失构建会失败)"
|
||||
fi
|
||||
deploy_from="local"
|
||||
;;
|
||||
dev@*) deploy_from="dev@$tov" ;;
|
||||
release@*) deploy_from="release@$tov" ;;
|
||||
local@*|dev@*) deploy_from="dev@$tov" ;;
|
||||
release@*) deploy_from="release@$tov" ;;
|
||||
esac
|
||||
c_info "[$name] 更新:$from → $tov($deploy_from)"
|
||||
hist_event update begin "$(read_pid)" "from=$from to=$tov"
|
||||
|
||||
Reference in New Issue
Block a user