Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8a335d5ba | ||
|
|
45687bcf67 | ||
|
|
178e74b403 | ||
|
|
a37f06352c |
@@ -1,7 +1,15 @@
|
|||||||
.git
|
.git
|
||||||
|
.gitea
|
||||||
node_modules
|
node_modules
|
||||||
.opencode/node_modules
|
.opencode/node_modules
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
.local.env
|
.local.env
|
||||||
dist
|
dist
|
||||||
.vscode
|
.vscode
|
||||||
|
data
|
||||||
|
logs
|
||||||
|
source
|
||||||
|
coverage
|
||||||
|
test-results
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: Agent CI/CD
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-test-publish-and-deploy:
|
||||||
|
uses: OrgTJWater/ci-templates/.gitea/workflows/container-cd.yml@main
|
||||||
|
with:
|
||||||
|
image_name: gitea.waternetwork.cn/orgtjwater/next-tjwater-agent
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
build_context: .
|
||||||
|
test_target: build
|
||||||
|
deploy_service: next-agent
|
||||||
|
deploy_host: 192.168.1.114
|
||||||
|
secrets:
|
||||||
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
DEV_DEPLOY_SSH_KEY: ${{ secrets.DEV_DEPLOY_SSH_KEY }}
|
||||||
+14
-15
@@ -1,15 +1,17 @@
|
|||||||
FROM oven/bun:canary-slim AS bun-bin
|
FROM oven/bun:canary-slim@sha256:24a8816a7388dd900e851b61b6d44a4a1908f464661a9ffe393e13e661f0ae3e AS bun-bin
|
||||||
|
|
||||||
FROM smanx/opencode:latest AS base
|
FROM smanx/opencode:1.18.13@sha256:b976acda21efffacd44abd7847dac7d646910dbaa477d1877e2881b39cf22a91 AS base
|
||||||
USER root
|
USER root
|
||||||
ARG UBUNTU_APT_MIRROR=mirrors.aliyun.com
|
ARG UBUNTU_APT_MIRROR=mirrors.aliyun.com
|
||||||
ARG PYPI_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
ARG PYPI_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
ARG PYPI_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
|
ARG PYPI_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
|
||||||
|
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
||||||
ENV VIRTUAL_ENV=/opt/venv
|
ENV VIRTUAL_ENV=/opt/venv
|
||||||
ENV PATH="$VIRTUAL_ENV/bin:/root/.local/bin:$PATH"
|
ENV PATH="$VIRTUAL_ENV/bin:/root/.local/bin:$PATH"
|
||||||
ENV PIP_INDEX_URL=${PYPI_INDEX_URL}
|
ENV PIP_INDEX_URL=${PYPI_INDEX_URL}
|
||||||
ENV PIP_TRUSTED_HOST=${PYPI_TRUSTED_HOST}
|
ENV PIP_TRUSTED_HOST=${PYPI_TRUSTED_HOST}
|
||||||
ENV UV_INDEX_URL=${PYPI_INDEX_URL}
|
ENV UV_INDEX_URL=${PYPI_INDEX_URL}
|
||||||
|
ENV BUN_CONFIG_REGISTRY=${NPM_REGISTRY}
|
||||||
|
|
||||||
RUN sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http://security.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true && \
|
RUN sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http://security.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true && \
|
||||||
sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http://security.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g" /etc/apt/sources.list.d/*.sources 2>/dev/null || true && \
|
sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http://security.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g" /etc/apt/sources.list.d/*.sources 2>/dev/null || true && \
|
||||||
@@ -19,14 +21,14 @@ RUN sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http:/
|
|||||||
unzip \
|
unzip \
|
||||||
python3 \
|
python3 \
|
||||||
python3-venv && \
|
python3-venv && \
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
|
||||||
ln -s /root/.local/bin/uv /usr/local/bin/uv && \
|
|
||||||
ln -sf /usr/bin/python3 /usr/local/bin/python && \
|
ln -sf /usr/bin/python3 /usr/local/bin/python && \
|
||||||
mkdir -p /root/.config/pip && \
|
mkdir -p /root/.config/pip && \
|
||||||
printf "[global]\nindex-url = %s\ntrusted-host = %s\n" "$PIP_INDEX_URL" "$PIP_TRUSTED_HOST" > /root/.config/pip/pip.conf && \
|
printf "[global]\nindex-url = %s\ntrusted-host = %s\n" "$PIP_INDEX_URL" "$PIP_TRUSTED_HOST" > /root/.config/pip/pip.conf && \
|
||||||
uv venv "$VIRTUAL_ENV" && \
|
python3 -m venv "$VIRTUAL_ENV" && \
|
||||||
uv pip install --python "$VIRTUAL_ENV/bin/python" \
|
pip install \
|
||||||
--index-url "$UV_INDEX_URL" \
|
--index-url "$PIP_INDEX_URL" \
|
||||||
|
--trusted-host "$PIP_TRUSTED_HOST" \
|
||||||
|
uv \
|
||||||
pip \
|
pip \
|
||||||
setuptools \
|
setuptools \
|
||||||
wheel \
|
wheel \
|
||||||
@@ -37,6 +39,7 @@ RUN sed -i "s|http://archive.ubuntu.com|https://${UBUNTU_APT_MIRROR}|g; s|http:/
|
|||||||
rich \
|
rich \
|
||||||
ipython \
|
ipython \
|
||||||
pytest && \
|
pytest && \
|
||||||
|
ln -s "$VIRTUAL_ENV/bin/uv" /usr/local/bin/uv && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY --from=bun-bin /usr/local/bin/bun /usr/local/bin/bun
|
COPY --from=bun-bin /usr/local/bin/bun /usr/local/bin/bun
|
||||||
@@ -54,29 +57,25 @@ WORKDIR /app
|
|||||||
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY --from=deps /app/.opencode/node_modules ./.opencode/node_modules
|
COPY --from=deps /app/.opencode/node_modules ./.opencode/node_modules
|
||||||
|
COPY package.json bun.lock ./
|
||||||
COPY tsconfig.json opencode.json README.md .gitignore ./
|
COPY tsconfig.json opencode.json README.md .gitignore ./
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
COPY .opencode ./.opencode
|
COPY .opencode ./.opencode
|
||||||
RUN bun run check
|
RUN bun run check
|
||||||
|
|
||||||
FROM base AS runner
|
FROM build AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
ENV PORT=8787
|
ENV PORT=8787
|
||||||
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
|
||||||
COPY --from=deps /app/.opencode/node_modules ./.opencode/node_modules
|
|
||||||
COPY package.json bun.lock ./
|
|
||||||
COPY tsconfig.json opencode.json .gitignore ./
|
|
||||||
COPY src ./src
|
|
||||||
COPY .opencode ./.opencode
|
|
||||||
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|
||||||
EXPOSE 8787
|
EXPOSE 8787
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
||||||
|
CMD curl --fail --silent --show-error "http://127.0.0.1:${PORT}/health" >/dev/null || exit 1
|
||||||
CMD ["bun", "src/server.ts"]
|
CMD ["bun", "src/server.ts"]
|
||||||
|
|||||||
@@ -99,3 +99,14 @@ bun test tests/**/*.test.ts
|
|||||||
```
|
```
|
||||||
|
|
||||||
`bun run check` 会检查服务代码和 `.opencode` 工具的类型。
|
`bun run check` 会检查服务代码和 `.opencode` 工具的类型。
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
Gitea Actions 通过 `.gitea/workflows/package.yml` 复用
|
||||||
|
`OrgTJWater/ci-templates` 的容器发布流程。手动触发只构建镜像并在 Dev
|
||||||
|
服务器运行候选验证;从 `main` 创建并推送 `v*` tag 后,候选验证通过才会
|
||||||
|
提升为正式 `agent` 服务。
|
||||||
|
|
||||||
|
仓库需要配置 `REGISTRY_USERNAME`、`REGISTRY_PASSWORD` 和
|
||||||
|
`DEV_DEPLOY_SSH_KEY` 三个 Gitea Secrets。`.env`、持久化数据、日志和
|
||||||
|
`source/` 业务数据不会写入镜像;它们由 Dev 服务器通过环境文件和卷挂载。
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"model": "deepseek/deepseek-v4-flash",
|
"model": "deepseek/deepseek-v4-flash",
|
||||||
|
"experimental": {
|
||||||
|
"continue_loop_on_deny": true
|
||||||
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"hostname": "127.0.0.1",
|
"hostname": "127.0.0.1",
|
||||||
"port": 4096
|
"port": 4096
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
|
||||||
|
describe("OpenCode runtime config", () => {
|
||||||
|
test("continues the agent loop after a question or permission is denied", async () => {
|
||||||
|
const config = await Bun.file(new URL("../../opencode.json", import.meta.url)).json();
|
||||||
|
|
||||||
|
expect(config.experimental?.continue_loop_on_deny).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user