Why: The research record, HTML cleaning, listen guard, secret store, and context controls land together, and the parent pointers have to name those commits. Evidence: Child commits are core bd63223, agent-native 3a110a7, ui d76a8e6, frontend 36b92ed, documents f3f823e, backend 42cca8f. svc.sh forwards the listen switches and info prints them. Impact: A reverse proxy or a LAN hostname needs allowedHosts or an unauthenticated host check returns 403. Startup moves raw API keys into the secret table after a settings snapshot. Refs: .task/feature-sillytavern-review.md Co-authored-by: Cursor <cursoragent@cursor.com>
721 lines
35 KiB
Markdown
721 lines
35 KiB
Markdown
# svc.sh 使用说明
|
||
|
||
`scripts/svc.sh` 是本仓的**本机服务管理器**:把 后端(agent)、前端静态服务(static)、
|
||
PostgreSQL 数据库(postgres)三类服务统一为"服务"模型——按提交/版本部署、生命周期管理、
|
||
配置分层持久化、标签、事件追溯,以及一套完整的数据库运维能力(换端口 / 备份 / 恢复 /
|
||
克隆 / 跨实例搬库)。
|
||
|
||
设计原则(也是安全边界,详见 [§11 安全与边界](#11-安全与边界)):
|
||
|
||
- **服务自包含**:每个服务的产物、数据、日志、登记都在 `runtime/<name>/` 一个目录里,
|
||
服务之间互不串版本;删目录 = 完全移除。
|
||
- **登记持久化**:所有状态落盘(`svc.env` 当前态 + `history.jsonl` 事件流),`list` /
|
||
`history` 全部从文件重建,脚本无内存状态、跨会话可追溯。
|
||
- **不碰现场**:不改主检出 git 状态;只停"自己 pidfile + cmdline 双校验"通过的进程;
|
||
端口冲突报错不抢;除 `--from local` 外的构建全部在隔离 worktree(物化自独立部署
|
||
源仓,与当前工作区状态无关——脏树、任意分支均可部署/更新)。
|
||
|
||
分主题速查:`scripts/svc.sh help [model|deploy|lifecycle|db|dbops|config|examples|safety]`;
|
||
本文档与 `--help` 内容同源,以实现为准。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [前提条件](#1-前提条件)
|
||
2. [90 秒上手](#2-90-秒上手)
|
||
3. [概念与目录布局](#3-概念与目录布局)
|
||
4. [命令参考:服务级](#4-命令参考服务级)
|
||
5. [命令参考:部署来源](#5-命令参考部署来源)
|
||
6. [命令参考:全局命令](#6-命令参考全局命令)
|
||
7. [命令参考:数据库](#7-命令参考数据库)
|
||
8. [数据库运维手册](#8-数据库运维手册)
|
||
9. [配置系统](#9-配置系统)
|
||
10. [登记文件与事件流](#10-登记文件与事件流)
|
||
11. [安全与边界](#11-安全与边界)
|
||
12. [退出码](#12-退出码)
|
||
13. [故障排查](#13-故障排查)
|
||
14. [配方索引](#14-配方索引)
|
||
|
||
---
|
||
|
||
## 1. 前提条件
|
||
|
||
| 依赖 | 用途 | 必需性 |
|
||
|---|---|---|
|
||
| bash ≥ 4、git | 脚本本体与提交物化 | 必需 |
|
||
| curl | 健康检查、设置播种 | 必需 |
|
||
| python3 | static 服务(http.server)、播种 payload | static/播种需要 |
|
||
| ss | 端口占用检测(`iproute2`) | 建议(缺失时跳过检测) |
|
||
| PostgreSQL 工具链(initdb/pg_ctl/psql/pg_dump/pg_restore/pg_isready) | 数据库功能 | 数据库功能需要 |
|
||
|
||
PostgreSQL 工具链定位顺序:`SVC_PG_BIN` 环境变量 → `pg_config --bindir` →
|
||
`/usr/lib/postgresql/*/bin` 等常见路径。都没有时 agent/static 功能不受影响。
|
||
|
||
## 2. 90 秒上手
|
||
|
||
```bash
|
||
# 一套演示后端(缺省部署远端 main 最新:独立部署源仓物化构建 → 启动 → 健康检查;
|
||
# 与当前工作区状态无关。要构建当前工作区:--from local)
|
||
scripts/svc.sh dev deploy --mock
|
||
|
||
# 一个数据库 + 让后端连上它
|
||
scripts/svc.sh db create pg1 --port 8890 # initdb,只登记不启动
|
||
scripts/svc.sh pg1 start # pg_ctl 启动 + 自动建库 + pg_isready
|
||
scripts/svc.sh prod deploy --from dev@<sha> \
|
||
--dsn "$(scripts/svc.sh db dsn pg1 --reveal)" # DSN 直接组合进部署
|
||
scripts/svc.sh prod db pg1 --db prod # 或事后绑定/切换(缺库自动建,重启生效)
|
||
scripts/svc.sh prod config .svc/prod.json # 指定/更换配置文件(校验+重启即时生效)
|
||
|
||
# 日常操作
|
||
scripts/svc.sh list # 全服务总览(含 DB 绑定列)
|
||
scripts/svc.sh info # 综合报告:运行服务/数据库/配置快照
|
||
scripts/svc.sh prod db # 查看 prod 的数据库绑定与可用实例
|
||
scripts/svc.sh pg1 restart # 重启(复用上次配置)
|
||
scripts/svc.sh prod logs 100 # 跟日志
|
||
scripts/svc.sh history # 事件追溯
|
||
|
||
# 备份 / 恢复 / 克隆
|
||
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 # 自动更新过时且运行中的服务
|
||
```
|
||
|
||
## 3. 概念与目录布局
|
||
|
||
### 3.1 服务名
|
||
|
||
`^[a-z][a-z0-9-]{0,15}$`(小写字母开头,可含数字与连字符,≤16 位)。保留字不可用作
|
||
服务名:`status list add set db rm create dsn commits history update deploy stop start
|
||
restart logs help info version`。
|
||
|
||
三个名字有默认端口:`dev` = `127.0.0.1:8788`,`prod` = `127.0.0.1:8787`;其余名字按
|
||
名称哈希在 **8800–9099** 确定性派生端口,与已登记端口或正在监听的端口冲突时自动向后
|
||
扫描;`SVC_<NAME>_ADDR` 可显式覆盖。
|
||
|
||
### 3.2 目录布局
|
||
|
||
每个服务自包含于一个目录(`--purge` 删目录即完全移除):
|
||
|
||
```
|
||
runtime/<name>/
|
||
├── bin/agent-system agent 产物(deploy 复制就位;start 只跑这份)
|
||
├── htdocs/ static 前端产物(--dir 模式登记外部目录,不复制)
|
||
├── data/ agent 数据(SQLite 与工件;--data 可改)
|
||
├── pgdata/ postgres 数据(initdb 产物,700)
|
||
├── plugins/ agent 插件(随 deploy 复制)
|
||
├── backups/ pg_dump 备份(目录 700,文件 600)
|
||
├── svc.pid pidfile
|
||
├── svc.log | pg.log 日志(postgres 用 pg.log)
|
||
├── svc.env 登记 + 持久化配置(dotenv,600)——见 §10
|
||
└── history.jsonl 事件流(append-only JSON Lines)——见 §10
|
||
```
|
||
|
||
因为产物在环境目录内,`start`/`restart` 不依赖主检出;**旧版脚本部署过的环境没有环境
|
||
产物,升级后首次需重新 deploy 一次**(脚本会明确提示)。
|
||
|
||
### 3.3 三类服务(kind)
|
||
|
||
| kind | 产物 | 数据 | 生命周期实现 |
|
||
|---|---|---|---|
|
||
| `agent` | 单二进制(内嵌前端) | `data/`(SQLite)或外部 DSN | nohup + TERM→KILL |
|
||
| `static` | `htdocs/` | 无 | `python3 http.server` |
|
||
| `postgres` | 系统工具链 | `pgdata/` | `pg_ctl`(fast stop,绝不 KILL) |
|
||
|
||
登记里没有 `kind=` 的旧条目自动视为 `agent`。同名服务不能换类型,需先 `rm`。
|
||
|
||
## 4. 命令参考:服务级
|
||
|
||
以下 `<name>` 均指服务名;`action` 可省略的只有 `deploy`。
|
||
|
||
### 4.1 deploy(部署并启动)
|
||
|
||
```
|
||
scripts/svc.sh <name> deploy [--kind agent|static] [--from 源] [--tag T]... [参数...]
|
||
```
|
||
|
||
流程:解析来源 →(dry-run 则只打印计划)→ 停旧实例 → 物化/构建/校验 → 产物复制到
|
||
`runtime/<name>/` → 启动 → 健康等待(agent 20s / static 10s)→ 播种设置(agent)→
|
||
登记。任何一步失败都会写 `deploy fail` 事件并保留现场。
|
||
|
||
**agent**:来源见 [§5](#5-命令参考部署来源);启动参数组装见 [§9 配置系统](#9-配置系统);
|
||
健康后按 `--model-*` / `--light-*` / `--tavily-keys` 播种(幂等,设置存在 agent 数据目录)。
|
||
|
||
**static**:
|
||
|
||
```bash
|
||
scripts/svc.sh ui deploy --kind static --from dev@<sha> # 构建该提交的 frontend dist → htdocs/
|
||
scripts/svc.sh ui deploy --kind static --dir ../dist # 直接服务既有目录(不构建不复制)
|
||
```
|
||
|
||
- `--dir` 模式登记原始路径(`source=dir@<路径>`),目录内容由你自己管理;
|
||
- `release` 源对 static 无意义(制品内嵌前端),明确拒绝。
|
||
|
||
**通用参数**:
|
||
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `--tag T` | 标签,可重复;登记合并去重,`list --tag` 过滤 |
|
||
| `--addr host:port` / `--host H` / `--port P` | 监听地址 |
|
||
| `--data DIR` | agent 数据目录(默认 `runtime/<name>/data`) |
|
||
| `--plugins DIR` | agent 插件源(默认随 deploy 复制环境目录的 `plugins/`) |
|
||
| `--dsn DSN` / `--auth on\|off\|auto` / `--mock` | agent 运行参数(非 dev 环境默认 `--auth auto`) |
|
||
| `SVC_<NAME>_INSECURE_LISTEN` | 设为 `1` 时允许该服务在非回环地址上不开启认证。值传给进程的 `AGENT_SYSTEM_INSECURE_LISTEN`,不写进 `exec=`。旧二进制会忽略 |
|
||
| `SVC_<NAME>_ALLOWED_HOSTS` | 逗号分隔的额外主机名,传给 `AGENT_SYSTEM_ALLOWED_HOSTS`,供反向代理的 Host / Origin 校验 |
|
||
| `--model-base/--model-key/--model-name`、`--light-*`、`--tavily-keys` | 启动健康后播种 |
|
||
| `--dry-run` | 只解析并打印部署计划(来源、物化路径、产物去向、启动参数) |
|
||
| `--pick [dev\|release]` | 交互式编号选提交(需 TTY) |
|
||
| `--config FILE` / `--env FILE` | 配置文件(见 §9) |
|
||
| `-- <剩余参数>` | 原样透传给 `agent-system serve` |
|
||
|
||
### 4.2 start / stop / restart / logs / status
|
||
|
||
```bash
|
||
scripts/svc.sh <name> start # 已在运行则提示并返回 0
|
||
scripts/svc.sh <name> stop # agent/static: TERM→10s→KILL;postgres: pg_ctl -m fast
|
||
scripts/svc.sh <name> restart # stop + start
|
||
scripts/svc.sh <name> logs [N] # tail -f,从最近 N 行起(默认 50)
|
||
scripts/svc.sh <name> status # 单服务详情
|
||
```
|
||
|
||
- **裸 `restart` 复用上次启动配置**(svc.env `exec=`),换过端口/参数不用重敲;
|
||
- 显式给任何运行参数(或 `--config` 文件、`SVC_*` 变量)时**整体重建**参数;
|
||
- agent/static 换端口:`restart --port N`(进程与登记同步更新);
|
||
- postgres 换端口:`set --apply`(见 §7.4)或 `restart --port N` 同样有效。
|
||
|
||
`status` 输出示例(postgres):
|
||
|
||
```
|
||
[pg1] postgres 运行中 pid=3115294
|
||
地址 127.0.0.1:8890 数据 /…/runtime/pg1/pgdata
|
||
来源 postgres@local 版本 18.6
|
||
标签 core,local
|
||
库 app 用户 agent
|
||
DSN postgresql://agent:***@127.0.0.1:8890/app(db dsn pg1 --reveal 看密码)
|
||
```
|
||
|
||
### 4.3 set(变更登记)
|
||
|
||
```bash
|
||
scripts/svc.sh set <name> --tag T... # 三类服务通用:改标签(不动进程)
|
||
scripts/svc.sh set <pg名> --port N [--host H] # 未运行:直接改登记
|
||
scripts/svc.sh set <pg名> --port N --apply # 运行中:停止 → 改登记 → 重启
|
||
scripts/svc.sh set <pg名> --host 0.0.0.0 --apply # 换绑定主机同理
|
||
```
|
||
|
||
- 运行中的 postgres **必须** `--apply`,否则拒绝(防止登记地址与实际监听不一致);
|
||
- 新端口先做双重校验:未被其他服务登记占用、且当前无人监听;
|
||
- `--apply` 的重启走 `pg_ctl` 优雅停机,数据安全;
|
||
- agent/static 的地址变更用 `restart --port N`(set 只改登记,会提示)。
|
||
|
||
### 4.4 rm(注销)
|
||
|
||
```bash
|
||
scripts/svc.sh rm <name> # 停止 + 移除登记(svc.env/svc.pid);目录数据历史保留
|
||
scripts/svc.sh rm <name> --purge # 连 runtime/<name>/ 整个目录一起删除(含备份!)
|
||
```
|
||
|
||
只管理本脚本登记过的服务;未登记名字会明确报错。
|
||
|
||
### 4.5 db(agent 服务的数据库绑定/切换)
|
||
|
||
```bash
|
||
scripts/svc.sh <agent名> db # 查看当前绑定 + 可用实例
|
||
scripts/svc.sh <agent名> db <pg名> [--db X] # 绑定/切换数据库
|
||
scripts/svc.sh <agent名> db <pg名> --no-restart # 只改登记,下次 start 生效
|
||
scripts/svc.sh <agent名> db --clear # 解除绑定(回内嵌 SQLite 档)
|
||
```
|
||
|
||
每个 agent 服务都可以对应一个数据库实例中的库;绑定后 DSN 持久化在 `svc.env`
|
||
(`exec=` 的 `--dsn` + `dbref=<pg名>/<库名>`,权限 600),跨重启保留。
|
||
|
||
- **缺库自动建**:实例运行中且目标库不存在时自动 `CREATE DATABASE`(幂等);
|
||
实例未运行且目标库非其默认库 → 提示先 `start` 实例;
|
||
- **运行中自动重启生效**(复用新 `exec=`);`--no-restart` 只写登记;
|
||
- **旧产物预检**:当前二进制不识别 `--dsn` 时警告(绑定已登记但重启按内嵌档跑);
|
||
- 展示:`list` 的 **DB 列**、`status` 的"数据库"行、`info` 数据库节的**绑定服务**行
|
||
(反向映射:哪些服务指向该实例)都能看到服务↔数据库对应关系;
|
||
- 未用本命令、直接 `deploy --dsn` 的服务,显示层会按 DSN 的 host:port 反查匹配已
|
||
登记实例(显示 `<pg名>/<库>`;匹配不上显示 `外部@host:port`);
|
||
- `--clear` 后服务回到内嵌 SQLite 档(数据在原 `--data` 目录,切回即见旧数据)。
|
||
|
||
### 4.6 config(agent 服务的配置文件更新/生效)
|
||
|
||
```bash
|
||
scripts/svc.sh <agent名> config # 查看当前配置文件(掩码内容 + agent 视角生效值)
|
||
scripts/svc.sh <agent名> config <file.json> # 更换使用的配置文件(校验通过才切换)
|
||
scripts/svc.sh <agent名> config <file> --no-restart # 只改登记,下次 start 生效
|
||
scripts/svc.sh <agent名> config --clear # 移除(回命令行参数形态)
|
||
```
|
||
|
||
配置文件是 agent 二进制的 `--config`(JSON,schema 严格校验;可用
|
||
`agent-system config explain -config <file>` 预览每个键的来源与生效值)。
|
||
|
||
- **切换前强校验**:文件必须存在且通过二进制的 schema 校验(未知键/非法值直接拒绝,
|
||
不会把服务重启进坏配置);旧产物不识别 `--config` 时警告;
|
||
- **即时生效**:运行中的服务自动重启应用新配置(agent 无 SIGHUP 热重载,重启秒级);
|
||
绑定后日常改配置 = 编辑文件 + `restart`(或重跑 `config <同一文件>` 再校验一遍);
|
||
- 持久化:`exec=` 的 `--config <绝对路径>` + `conffile=` 键(跨重启保留,600);
|
||
- 展示:`status`/`info <name>` 的"配置文件"行、`info` 配置节的文件内容快照
|
||
(敏感值掩码,`info --reveal` 显示明文);文件丢失时明确告警并提示恢复或 `--clear`。
|
||
|
||
## 5. 命令参考:部署来源
|
||
|
||
`deploy --from` 支持三种来源(**缺省 = `dev` 远端最新**),agent 与 static 共用:
|
||
|
||
### 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
|
||
```
|
||
|
||
在主检出跑 `make build`(agent)或 `make frontend`(static),产物复制到服务目录。
|
||
**这是唯一会写主检出的路径**,写的都是 gitignore 目录(`bin/`、`node_modules/`、
|
||
`modules/frontend/dist/`),不产生任何 git 状态变化;也是**唯一依赖当前工作区状态**
|
||
的来源。适合"把我现在的工作区跑起来"。
|
||
|
||
### 5.3 release@\<版本\> —— Releases 仓制品
|
||
|
||
```
|
||
--from release # Releases 仓最新(HEAD)
|
||
--from release@0.1.0 # 指定版本号
|
||
--from release@43ac28d # 指定 Releases 仓提交也可
|
||
```
|
||
|
||
制品取 `<Releases>/build/<v>/agent-system`(+ `plugins/`),**sha256 对
|
||
`versions/<v>/manifest.json` 校验,不符即拒绝部署**;并回显该版本对应的 Dev 提交。
|
||
仓库定位:`SVC_RELEASES_DIR` > `../Agent-System-Releases`。制品缺失时提示先在
|
||
Releases 仓跑 `scripts/build-release.sh <v>`。
|
||
|
||
### 5.4 辅助
|
||
|
||
```bash
|
||
scripts/svc.sh commits [dev|release] [N] # 可部署提交表(默认 20 条)
|
||
scripts/svc.sh <name> deploy --pick # 交互式编号选择
|
||
scripts/svc.sh <name> deploy --dry-run # 只打印计划
|
||
```
|
||
|
||
`commits` 表格:dev 源标注 `[最新]`(源仓 origin/main 顶)与 `[已部署:<服务名>]`
|
||
(从各服务 `svc.env source=` 汇总);release 源额外给出版本号与对应 Dev 提交。
|
||
|
||
## 6. 命令参考:全局命令
|
||
|
||
### 6.1 list / status(总览)
|
||
|
||
```bash
|
||
scripts/svc.sh list [--tag T] # status 等价
|
||
```
|
||
|
||
扫描 `runtime/*/svc.env` 枚举全部已登记服务:
|
||
|
||
```
|
||
NAME KIND STATE PID ADDR DB SOURCE TAGS
|
||
pg1 postgres 运行中 3115294 127.0.0.1:8890 - postgres@local core,local
|
||
prod agent 运行中 3117059 127.0.0.1:8791 pg1/prod release@0.1.0 stable
|
||
ui-qa static 未运行 - 127.0.0.1:9054 - dir@/tmp/static-demo ui
|
||
```
|
||
|
||
DB 列:agent 服务当前绑定的 `<pg名>/<库名>`(见 §4.5;外部 DSN 显示 `外部@host:port`,
|
||
未绑定显示 `-`)。
|
||
|
||
STATE 的判定:pidfile 存在且 `/proc/<pid>/cmdline` 匹配登记的 `pidcheck` 标记
|
||
(agent=二进制路径、postgres=pgdata 路径、static=`--directory <目录>`)。进程被人手动
|
||
杀掉后 STATE 自动落回"未运行",不会误报。
|
||
|
||
### 6.2 info(综合信息报告,只读)
|
||
|
||
```bash
|
||
scripts/svc.sh info [name] [--tag T] [--reveal]
|
||
```
|
||
|
||
一条命令看全本机现场:**正在运行哪些服务、有哪些数据库(含实例内部库)、每个服务
|
||
的配置文件与内容快照**。全程只读,不改任何登记、进程与文件。
|
||
|
||
| 用法 | 行为 |
|
||
|---|---|
|
||
| `info` | 全景报告(下述五节全量) |
|
||
| `info pg1` | 单服务深度报告:状态详情 +(postgres)实例与内部库 + 配置快照 + 最近事件 |
|
||
| `info --tag core` | 服务名/数据库/配置/事件均按标签过滤(与 `list --tag` 同语义) |
|
||
| `info --reveal` | 显示默认掩码的敏感值(DB 密码、API key、DSN 密码) |
|
||
|
||
报告分节(整体走 stdout,可直接 `> snapshot.txt` 整页保存):
|
||
|
||
1. **服务**——`list` 同款表格(含 **DB 绑定列**)+ 汇总行(`N 已登记 / M 运行中(agent a、postgres p、static s)`);
|
||
2. **数据库**——每个 postgres 实例一屏:运行状态/地址、版本/用户/认证/默认库/来源、
|
||
**绑定服务**(哪些 agent 服务指向该实例,见 §4.5)、数据目录与体量、备份份数与
|
||
最近一份;**运行中的实例直接列出内部数据库及大小**(未运行则注明内部库不可见);
|
||
3. **配置**——逐服务 `runtime/<name>/svc.env` 的文件路径、权限与逐行内容快照,加上
|
||
全局层:`.svc.env`(自动加载层)、本次 `--config/--env` 文件、shell 已导出的
|
||
`SVC_*` 变量;
|
||
4. **最近事件**——各服务 history 最近 5 条(完整历史走 `history`)。
|
||
|
||
敏感值默认掩码:`password=` 键、键名含 `KEY/PASS/SECRET/TOKEN/DSN` 的值整段掩为
|
||
`***`,`exec=` 里 DSN 的密码段同样掩码;`--reveal` 才显示明文。掩码规则与
|
||
`db dsn`(默认掩密码)一致,便于把报告贴进工单/日志而不泄密。
|
||
|
||
### 6.3 history(事件追溯)
|
||
|
||
```bash
|
||
scripts/svc.sh history [name] [N] # 默认全部服务、最近 20 条;首参为纯数字时视为条数
|
||
```
|
||
|
||
合并各服务 `history.jsonl`(按时间排序),字段:时间 / 服务 / kind / 事件 / 结果 /
|
||
来源 / pid / 详情。事件类型见 §10.2。
|
||
|
||
### 6.4 update(自动检索并更新)
|
||
|
||
```bash
|
||
scripts/svc.sh update [name...] [--check] [--all] [--no-fetch]
|
||
```
|
||
|
||
把服务刷到远端最新:fetch 独立部署源仓 → 逐服务比较登记来源与最新 → 报告并(可选)
|
||
更新。**全程不依赖当前工作区状态**(主检出脏树、任意分支均可更新)。
|
||
|
||
| 用法 | 行为 |
|
||
|---|---|
|
||
| `update --check` | 只输出检测表,不改任何状态 |
|
||
| `update` | 自动更新所有"过时且**运行中**"的服务 |
|
||
| `update dev pg1` | 点名更新(已停止的过时服务也会更新并启动) |
|
||
| `update --all` | 范围扩大到已停止服务 |
|
||
| `update --no-fetch` | 跳过网络 fetch,用本地已有引用比较(报告注明) |
|
||
|
||
检测表输出:服务 / 当前来源 / 最新 / 状态。状态含义:
|
||
|
||
- `✓ 最新`——登记来源与最新一致,不动作;
|
||
- `可更新`——本地来源是远端最新的祖先,将被更新;
|
||
- `领先远端 main(不动作)` / `与远端 main 分叉(不自动更新)` /
|
||
`提交不在远端(不自动更新)`——不盲目降级或强更;
|
||
- `不适用`——postgres(无代码版本)与 static `--dir`(外部目录)不参与。
|
||
|
||
各来源的更新动作(复用 deploy 全链路:停旧 → 构建/校验 → 启动 → 健康检查;持久化配置
|
||
与标签保留;写 `update` 事件入 history):
|
||
|
||
| 来源 | 更新方式 |
|
||
|---|---|
|
||
| `local@<sha>` / `dev@<sha>` | 一律 `deploy --from dev@<远端 main 最新>`(独立部署源仓 + 隔离 worktree 构建;不 pull 主检出、不看工作树状态) |
|
||
| `release@<版本>` | `deploy --from release@<Releases 最新版本>`(sha256 校验) |
|
||
|
||
任一服务失败不中断其余服务;最终汇总 `成功/失败/跳过`。退出码:0 全部成功或最新;
|
||
1 有失败;2 用法错误。
|
||
|
||
### 6.5 help
|
||
|
||
```bash
|
||
scripts/svc.sh # 一屏速览(短帮助)
|
||
scripts/svc.sh -h # 同上
|
||
scripts/svc.sh --help # 完整帮助(全部命令/参数/约束)
|
||
scripts/svc.sh help # 分主题清单
|
||
scripts/svc.sh help <主题> # 主题详解:model deploy lifecycle db dbops config examples safety
|
||
```
|
||
|
||
## 7. 命令参考:数据库
|
||
|
||
### 7.1 db create(创建实例)
|
||
|
||
```bash
|
||
scripts/svc.sh db create pg1 [--port 8890] [--host 127.0.0.1] \
|
||
[--user agent] [--password <pw>] [--db app] \
|
||
[--auth-mode scram-sha-256|md5] [--tag T]...
|
||
```
|
||
|
||
- `initdb` 到 `runtime/pg1/pgdata`(目录 700;密码经 pwfile 传递,即用即删);
|
||
- 默认用户 `agent`、默认库 `agent`、认证 `scram-sha-256`(pg_hba 全线);
|
||
- `--password` 缺省时自动生成(18 字节十六进制随机);
|
||
- **只登记不启动**——`scripts/svc.sh pg1 start` 启动;端口占用预检在 create 时已做。
|
||
|
||
### 7.2 start / stop / restart
|
||
|
||
- `start`:`pg_ctl -w -t 30 -l pg.log -o "-p <port> -k <环境目录> -c listen_addresses=…"`
|
||
——socket 目录指向环境目录(不落 pgdata,克隆时不随数据目录传播);
|
||
首次启动自动创建登记库(已存在则跳过);就绪判定 `pg_isready`;
|
||
- `stop`:`pg_ctl -m fast`(回滚事务、断连接、优雅退出);失败退 SIGTERM;
|
||
**SIGKILL 永远不用于 postmaster**;
|
||
- `restart`:stop + start。
|
||
|
||
### 7.3 db dsn / db ls
|
||
|
||
```bash
|
||
scripts/svc.sh db dsn pg1 # postgresql://agent:***@127.0.0.1:8890/agent(掩码)
|
||
scripts/svc.sh db dsn pg1 --reveal # 显示真实密码
|
||
scripts/svc.sh db dsn pg1 --db other # 指定库名
|
||
scripts/svc.sh db ls pg1 # 实例内数据库列表(须运行中)
|
||
```
|
||
|
||
DSN 走 stdout(提示走 stderr),可直接组合:`--dsn "$(scripts/svc.sh db dsn pg1 --reveal)"`。
|
||
|
||
### 7.4 换端口 / 换主机
|
||
|
||
见 §4.3 `set`。要点:运行中必须 `--apply`;登记、DSN、`pg_ctl` 启动参数联动更新;
|
||
数据不动。换端口 = 同机内"迁移"。
|
||
|
||
## 8. 数据库运维手册
|
||
|
||
### 8.1 备份
|
||
|
||
```bash
|
||
scripts/svc.sh db backup pg1 # 备份登记库
|
||
scripts/svc.sh db backup pg1 --db app # 指定库
|
||
scripts/svc.sh db backup pg1 --out /tmp/x.dump # 自定义输出路径
|
||
scripts/svc.sh db backups pg1 # 列表(时间 / 大小 / 文件名)
|
||
```
|
||
|
||
- 实现:`pg_dump -Fc` 走 TCP(实例须运行中),默认落到
|
||
`runtime/pg1/backups/<UTC时间戳>-<库>.dump`;
|
||
- 完成后 `pg_restore --list` 自检归档有效性,失败即删除该文件并记 `backup fail`;
|
||
- 备份**只增不删**;随 `rm --purge` 一并删除。
|
||
|
||
### 8.2 恢复
|
||
|
||
```bash
|
||
scripts/svc.sh db restore pg1 --file <dump> # 恢复到登记库
|
||
scripts/svc.sh db restore pg1 --file <dump> --db app2 # 恢复到指定库
|
||
scripts/svc.sh db restore pg1 --file <dump> --db app --force # 覆盖非空库
|
||
```
|
||
|
||
目标语义:
|
||
|
||
| 目标库状态 | 行为 |
|
||
|---|---|
|
||
| 不存在 | 建库 → 恢复 |
|
||
| 存在且无用户表 | 直接恢复 |
|
||
| 存在且有用户表 | **拒绝**;`--force` 才 `DROP DATABASE … WITH (FORCE)` → 重建 → 恢复 |
|
||
|
||
恢复前先校验文件是合法 pg_dump 归档;完成后回显恢复出的表数;全程事件入 history。
|
||
这是脚本里唯一可能删除数据的操作,必须显式 `--force` 解锁。
|
||
|
||
### 8.3 克隆实例(绑新端口)
|
||
|
||
```bash
|
||
scripts/svc.sh db clone pg1 pg1test --port 8896 # 物理克隆(默认)
|
||
scripts/svc.sh db clone pg1 pg1test --password newpw --tag test # 换密码/加标签
|
||
scripts/svc.sh db clone pg1 pg1test --online # 在线克隆(不停源)
|
||
```
|
||
|
||
**物理克隆(默认)**:源在运行则短暂 `pg_ctl -m fast` 停止(一致性要求)→
|
||
`cp -a pgdata`(剔除 `postmaster.pid` / `postmaster.opts`;socket 本就不在 pgdata)→
|
||
登记目标(端口 = `--port` 或派生;用户/库/认证继承,密码可 `--password` 覆盖;标签
|
||
继承 + `--tag` 追加;`source=clone@<源名>`)→ 自动复启源。**目标不自动启动**——按需
|
||
`scripts/svc.sh pg1test start`。
|
||
|
||
**`--online`**:不停源,把源的登记库 dump/restore 到目标——要求目标**已**
|
||
`db create` + `start`。适合源不能停的场景。
|
||
|
||
### 8.4 跨实例搬库
|
||
|
||
```bash
|
||
scripts/svc.sh db copy pgdev pgprod --db app # pgdev.app → pgprod.app
|
||
scripts/svc.sh db copy pgdev pgprod --db app --force # 目标非空时覆盖
|
||
```
|
||
|
||
- 双方实例都须运行中(走 TCP dump/restore);
|
||
- `--db X` 同时命名源库与目标库;缺省取源的登记库;
|
||
- 目标库非空须 `--force`(语义同 restore);成功后两侧 history 各记一条 `copy`。
|
||
|
||
### 8.5 端口规划建议
|
||
|
||
- 默认派生区 8800–9099 按服务名哈希,天然分散;多实例并存时建议显式 `--port` 分配
|
||
并记入标签(如 `--tag port-8896`);
|
||
- 换端口用 `set --apply`;克隆用 `--port` 指定;两者都会做占用双重校验。
|
||
|
||
## 9. 配置系统
|
||
|
||
### 9.1 优先级
|
||
|
||
```
|
||
命令行参数
|
||
> --config FILE(--env FILE 别名)
|
||
> svc.env 持久化(addr=、exec=)
|
||
> SVC_<NAME>_* 环境变量(.svc.env 自动加载,同层)
|
||
> 默认值
|
||
```
|
||
|
||
### 9.2 配置文件
|
||
|
||
dotenv 格式:`KEY=VALUE`,支持 `#` 注释、成对引号、`export` 前缀;只识别合法变量名,
|
||
**不 source 执行文件内容**(防注入)。建议 `.env.dev` / `.env.prod` 等加入 gitignore。
|
||
|
||
```bash
|
||
scripts/svc.sh prod deploy --config .env.prod
|
||
scripts/svc.sh prod deploy --env .env.prod # 等价
|
||
```
|
||
|
||
### 9.3 环境变量
|
||
|
||
| 变量 | 说明 |
|
||
|---|---|
|
||
| `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` | 轻量模型 |
|
||
| `SVC_TAVILY_KEYS` | Tavily 密钥池(逗号分隔) |
|
||
|
||
### 9.4 持久化语义
|
||
|
||
- `deploy`/`start` 成功后把当前态写入 `svc.env`(600):`addr`、`exec`(agent 上次
|
||
完整启动参数)等;
|
||
- 裸 `start`/`restart` 复用 `exec=`;任何显式参数(CLI、`--config`、`SVC_*`)出现即
|
||
**整体重建**启动参数;
|
||
- 标签合并去重、跨重启保留;postgres 的用户/密码/库名/认证模式持久化,重启不丢。
|
||
|
||
## 10. 登记文件与事件流
|
||
|
||
### 10.1 svc.env 字段
|
||
|
||
| 键 | 说明 |
|
||
|---|---|
|
||
| `kind` | `agent` / `static` / `postgres`(缺省视为 agent) |
|
||
| `env` | 服务名 |
|
||
| `pid` | 最近启动 pid |
|
||
| `addr` | 监听地址(持久化,下次 start 复用) |
|
||
| `tags` | 标签(逗号分隔) |
|
||
| `source` | 部署来源:`local@<sha>` / `dev@<sha>` / `release@<版本>` / `dir@<路径>` / `postgres@local` / `clone@<名>` |
|
||
| `version` | 产物版本串(`agent-system version` 输出) |
|
||
| `started` | 最近启动时间 |
|
||
| `pidcheck` | 进程判定标记(见 §6.1) |
|
||
| `exec` | agent 上次完整启动参数(含 `--dsn`,密码在其中) |
|
||
| `dbref` | agent 数据库绑定 `<pg名>/<库名>`(`<name> db` 命令写入,跨重启保留;见 §4.5) |
|
||
| `conffile` | agent 配置文件绝对路径(`<name> config` 命令写入,跨重启保留;见 §4.6) |
|
||
| `user` / `password` / `dbname` / `authmode` / `pgdata` | postgres 专属 |
|
||
| `htdocs` | static 专属 |
|
||
|
||
### 10.2 history.jsonl 事件
|
||
|
||
一行一个 JSON:`ts / event / env / kind / source / result / pid / addr / detail`。
|
||
|
||
| event | result | 触发 |
|
||
|---|---|---|
|
||
| `create` | ok | `db create` / 物理克隆登记 |
|
||
| `deploy` | begin / ok / fail | agent/static 部署全程 |
|
||
| `start` | ok / fail / warn | 启动(fail 含"进程即退/健康检查超时";warn 为进程起但探活未过) |
|
||
| `stop` | ok / fail | 停止(含 pg_ctl fast / SIGTERM 兜底说明) |
|
||
| `set` | ok | 登记变更(`addr 旧 → 新`;`db bind → <pg>/<库>` / `db unbind`) |
|
||
| `backup` | ok / fail | 备份(文件、大小) |
|
||
| `restore` | ok / fail | 恢复(库、文件、表数) |
|
||
| `clone` | ok / fail | 克隆(物理/在线) |
|
||
| `copy` | ok / fail | 搬库 |
|
||
| `update` | begin / ok / fail | 自动更新(from → to) |
|
||
| `rm` | ok | 注销(是否 purge) |
|
||
|
||
## 11. 安全与边界
|
||
|
||
- **写入边界**:只写 `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。
|
||
- **端口边界**:被他人占用报错不抢;显式端口双重校验(登记 + 监听);派生端口避让。
|
||
- **秘密与数据**:`svc.env`(含 DB 密码)与备份 600;环境/数据目录 700;DSN 默认掩码;
|
||
dotenv 不执行文件内容;`restore`/`copy` 覆盖非空库必须显式 `--force`;备份/克隆只增不删。
|
||
- **兼容承诺**:`kind=` 缺省视为 agent;旧格式 `svc.env`(仅 addr/data)在 `list`/
|
||
`status` 正常显示;旧产物二进制不识别的 `--dsn/--auth` 自动省略并提示。
|
||
|
||
## 12. 退出码
|
||
|
||
| 码 | 含义 |
|
||
|---|---|
|
||
| 0 | 成功(含"已在运行,无需操作") |
|
||
| 1 | 运行失败(构建失败、启动失败、校验不过、拒绝覆盖等) |
|
||
| 2 | 用法错误(未知参数/服务名/来源、缺参数、服务未登记等) |
|
||
|
||
## 13. 故障排查
|
||
|
||
| 症状 | 处置 |
|
||
|---|---|
|
||
| `端口被占用(非本服务)` | 按提示的占用者处理,或换端口(`--port` / `set --port --apply`) |
|
||
| `进程启动后即退出` | `scripts/svc.sh <name> logs 200` / postgres 看 `runtime/<name>/pg.log`;history 里有 fail 记录 |
|
||
| `20s 健康检查未通过` | 进程活着但未响应:查日志与端口;agent 常见原因是 DSN 指向未启动的库 |
|
||
| `该产物不支持 --dsn/--auth` | 提示而非错误:旧版本制品自动省略了不支持的 flag;需要该能力请部署新提交 |
|
||
| `环境产物缺失` | 该环境没有部署过(或旧版脚本部署):先 `deploy` |
|
||
| `pg_ctl start 失败` | 看 pg.log 常见:端口被占、pgdata 权限(须 700)、postmaster 残留 |
|
||
| `pidfile 指向的进程已不存在` | 脚本自动清理 pidfile;直接重新 start 即可 |
|
||
| `sha256 校验失败` | 制品与 manifest 不符:不要部署;在 Releases 仓重新 build |
|
||
| `部署源仓无此提交` | 源仓已自动 fetch 仍无此对象:确认 sha 正确(`scripts/svc.sh commits dev`) |
|
||
| `worktree 回收失败` | 按提示手动 `git -C <部署源仓> worktree remove --force runtime/.worktrees/<sha>` |
|
||
| `子模块物化失败` | 网络或子模块对象问题:重试(部署源仓会自动 fetch);或检查 git 远端可达性 |
|
||
| `目标库已有 N 张表——拒绝覆盖` | 确认后加 `--force`(会 drop 重建) |
|
||
| `提交不在远端(不自动更新)` | 该服务部署自未推送的本地提交(如 `--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
|
||
scripts/svc.sh pg1 start
|
||
scripts/svc.sh prod deploy --from dev@<sha> --dsn "$(scripts/svc.sh db dsn pg1 --reveal)"
|
||
|
||
# ③ 按提交部署 + 回退
|
||
scripts/svc.sh commits dev
|
||
scripts/svc.sh v1 deploy --from dev@73b2802 --tag test
|
||
scripts/svc.sh v1 deploy --from release@0.1.0
|
||
|
||
# ④ 双版本并行对比
|
||
scripts/svc.sh a deploy --from dev@<shaA> --port 8801
|
||
scripts/svc.sh b deploy --from dev@<shaB> --port 8802
|
||
|
||
# ⑤ 前端静态服务
|
||
scripts/svc.sh ui deploy --kind static --from dev@<sha>
|
||
scripts/svc.sh ui2 deploy --kind static --dir ../frontend/dist
|
||
|
||
# ⑥ 备份 → 改坏 → 恢复
|
||
scripts/svc.sh db backup pg1
|
||
scripts/svc.sh db restore pg1 --file runtime/pg1/backups/<最新>.dump --force
|
||
|
||
# ⑦ 克隆隔离环境
|
||
scripts/svc.sh db clone pg1 pg1test --port 8896
|
||
scripts/svc.sh pg1test start
|
||
scripts/svc.sh qa deploy --from dev@<sha> --dsn "$(scripts/svc.sh db dsn pg1test --reveal)"
|
||
|
||
# ⑧ 开发库搬到 prod 实例
|
||
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 # 只刷新指定服务
|
||
|
||
# ⑪ 总览与追溯
|
||
scripts/svc.sh list --tag test
|
||
scripts/svc.sh history pg1 50
|
||
```
|
||
|
||
---
|
||
|
||
*本文档对应 `scripts/svc.sh`(Agent-System-Dev 仓)。命令行为以实现为准;发现文档与
|
||
实现不一致时,以任务卡记录的方式提出修正。*
|