import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const OUT_DIR = join(ROOT, '_site');

function writeText(relativePath, content) {
  const target = join(OUT_DIR, relativePath);
  mkdirSync(dirname(target), { recursive: true });
  writeFileSync(target, content.trimStart(), 'utf8');
}

function copyIfExists(fromRelative, toRelative = fromRelative) {
  const source = join(ROOT, fromRelative);
  if (!existsSync(source)) return;
  const target = join(OUT_DIR, toRelative);
  mkdirSync(dirname(target), { recursive: true });
  cpSync(source, target, { recursive: true });
}

function escapeHtml(value) {
  return value
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;');
}

const manual = `# openHermit 安装与团队运维指南

这是一份给人和 Agent Loop 共同阅读的操作手册。目标不是展示源码，也不是营销介绍，而是说明如何安装 openHermit、如何创建团队、如何让 Agent Loop 按规则运维团队，以及出现问题时如何排障。

## 1. openHermit 是什么

openHermit 是一个本地运行的 AI 团队指挥台。它通过 cc-connect 管理 Claude Code、Codex、Gemini、Qoder 等 Agent 运行时，并把团队、任务、消息、定时循环、外部渠道统一到一个 Web 控制台中。

核心定位：

- 你负责定义目标、审批结果和处理例外。
- openHermit 负责团队看板、消息路由、任务状态和运行时管理。
- Agent Loop 负责持续检查任务、执行工作、回写证据和报告异常。

默认地址与目录：

- Web 控制台：\`http://127.0.0.1:5680\`
- 默认页面：\`/teams\`
- 本地状态目录：\`~/.hermit/\`
- cc-connect Management API：\`9820\`
- cc-connect Bridge：\`9810\`

## 2. 安装指南

### 2.1 普通用户安装

\`\`\`bash
npm install -g @yancyyu/openhermit
openhermit
\`\`\`

启动后打开：

\`\`\`text
http://127.0.0.1:5680
\`\`\`

常用命令：

\`\`\`bash
openhermit              # 启动 openHermit
open-hermit             # 等同于 openhermit
hermit                  # 等同于 openhermit
openhermit --port 8080  # 指定端口
openhermit --version    # 查看版本
openhermit update       # 检查并更新
\`\`\`

首次启动会自动准备本地配置。Agent 排障时只需要知道配置位置，不要打印里面的 token 或 secret：

\`\`\`text
~/.hermit/
  cc-connect/
    config.toml
  teams/
  logs/
\`\`\`

### 2.2 本地开发安装

\`\`\`bash
git clone https://github.com/yancyuu/Hermit.git
cd Hermit
pnpm install
pnpm dev
\`\`\`

开发模式默认打开：

\`\`\`text
http://localhost:5174
\`\`\`

开发和 CI 约定：

- 使用 \`pnpm\`，不要用 npm/yarn 做项目开发命令。
- 运行长日志命令时只保留尾部输出，例如 \`pnpm typecheck 2>&1 | tail -20\`。
- 不要把 \`~/.hermit/cc-connect/config.toml\`、token、secret、cookie 写入日志、文档或 memory。

## 3. 创建第一个团队

1. 打开 \`/teams\`。
2. 点击「新建团队」。
3. 填写团队名，例如 \`backend\`、\`frontend\`、\`qa\`。
4. 选择 harness，例如 \`claudecode\`、\`codex\`、\`gemini\`、\`qoder\`。
5. 绑定 cc-connect project。
6. 保存团队。
7. 在团队看板里创建任务，或通过外部渠道发送任务。
8. Agent Loop 认领任务、执行、回写结果。

推荐团队划分：

| 团队 | 推荐 harness | 负责内容 |
| --- | --- | --- |
| frontend | Claude Code / Qoder | UI、交互、前端缺陷 |
| backend | Claude Code / Codex | API、数据、服务逻辑 |
| qa | Gemini / Codex | 测试、回归、验收 |
| research | Gemini / Kimi | 调研、文档、竞品分析 |
| ops | Claude Code | CI、部署、运行状态、排障 |

## 4. 团队数据和运维目录

openHermit 自己的团队状态默认在：

\`\`\`text
~/.hermit/teams/<team-slug>/
  team.json          # 团队配置
  messages/group.jsonl
  tasks/board.json
\`\`\`

给数字员工长期运行的工作区建议这样组织：

\`\`\`text
/Users/distill/teams/
  .memory/
    rules/
    decisions/
    needs-review/
  .claude/
    skills/
    workflows/
  <team-folder>/
    .env
    CLAUDE.md
    00_index/
      conflict-review.md
    01_business-docs/
    03_data/
    07_memory/
    99_temp/
    .claude/
      skills/
\`\`\`

放置规则：

| 位置 | 放什么 | 禁止放什么 |
| --- | --- | --- |
| \`<team>/CLAUDE.md\` | 团队身份、边界、执行规则 | token、secret |
| \`<team>/07_memory/\` | 经过确认的团队长期事实 | 原始导出、临时日志 |
| \`.memory/needs-review/\` | 冲突事实、待审批提案 | 已确认事实 |
| \`.claude/skills/\` | 可复用操作能力 | 业务密钥 |
| \`.claude/workflows/\` | 稳定多步骤流程 | 临时笔记 |
| \`99_temp/\` | 临时材料 | 长期规则 |

## 5. Agent Loop 推荐工作流

Agent Loop 每轮执行时按这个顺序走：

1. 确认自己服务哪个 team。
2. 读取 team 的 \`CLAUDE.md\` 和必要的 \`07_memory/\`。
3. 查询 openHermit 团队状态、任务看板和最近消息。
4. 判断输入来源：看板任务、跨团队消息、外部渠道、定时任务、人工 DM。
5. 如果任务还没被明确启动，不要直接执行破坏性动作。
6. 认领或更新任务状态。
7. 执行最小安全步骤。
8. 保存证据：命令、结果、链接、截图或失败原因。
9. 回写任务评论或状态。
10. 如果动作会重复发生，把它升级为 skill、workflow 或 cron。
11. 如果发现事实冲突，写入 \`needs-review\` 并停止自动推进。

任务状态建议：

\`\`\`text
received -> in_progress -> completed -> approved
                    └── failed / blocked / needs-review
\`\`\`

## 6. 常用运维 Loop

### 6.1 团队健康检查

- 列出全部团队。
- 检查是否有离线、卡住、失败的 Agent。
- 检查最近消息和任务状态。
- 检查外部渠道绑定是否仍然有效。
- 输出报告：团队、症状、证据、建议动作。

### 6.2 任务派发检查

- 确认 source team 和 target team。
- 判断是普通消息还是正式任务派发。
- 正式派发前确认 Redis task bus 已配置。
- 目标团队未启动任务前，不要把消息当成已接受。
- 记录从 \`received\` 到 \`approved\` 的全过程。

### 6.3 记忆治理

- 稳定业务事实写到 \`<team>/07_memory/\`。
- 跨团队规则先写到 \`.memory/needs-review/\`，审批后再提升。
- 原始导出只放 data/report 路径，memory 只写指针。
- secret 永远不写进 memory、docs、messages 或日志。

### 6.4 CI / Pages 检查

- 每次提交后检查 GitHub Actions。
- 如果 \`Deploy Agent Runbook to GitHub Pages\` 失败，优先修 Pages workflow 或页面构建脚本。
- 如果普通 app CI 失败，但 Pages 成功且线上页面正确，不要把它误判为 page 问题。
- 验证线上页面必须包含：\`openHermit 安装与团队运维指南\` 和 \`Feishu/Lark CLI 团队隔离\`。

## 7. Feishu/Lark CLI 团队隔离

每个团队都应该有自己的 CLI profile。推荐使用 PATH 级 wrapper，而不是让 Agent 直接调用真实 \`lark-cli\`。

调用链：

\`\`\`text
Agent 在团队目录中调用 lark-cli
  -> PATH 命中 ~/.local/bin/lark-cli wrapper
  -> wrapper 从当前目录向上寻找最近的 .env
  -> wrapper 读取 LARK_CLI_PROFILE
  -> wrapper 调用真实 lark-cli 并自动附加 --profile <team-profile>
\`\`\`

团队 \`.env\` 模板：

\`\`\`bash
LARK_CLI_PROFILE=<team-folder-name>
LARK_CLI_BRAND=feishu
LARK_APP_ID=<app_id>
LARK_APP_SECRET=<app_secret>

# 如果团队使用 FEISHU 命名，也可以：
# FEISHU_APP_ID=<app_id>
# FEISHU_APP_SECRET=<app_secret>
\`\`\`

安全规则：

- \`LARK_CLI_PROFILE\` 可以打印。
- app id 按内部策略处理。
- app secret 绝不能打印、提交、写日志、写文档、写 memory。

执行任何飞书操作前先检查：

\`\`\`bash
pwd
command -v lark-cli
lark-cli config show
lark-cli profile list
\`\`\`

期望：

- \`command -v lark-cli\` 指向 \`~/.local/bin/lark-cli\`。
- \`lark-cli config show\` 显示当前团队 profile。
- 用户授权页显示当前团队 app 名称。

## 8. Feishu/Lark 排障表

| 症状 | 检查 | 修复 |
| --- | --- | --- |
| profile 错了 | \`pwd\`、最近 \`.env\`、\`lark-cli config show\` | cd 到正确团队目录，或显式传 \`--profile\` |
| Agent 子进程用了错误 app | \`command -v lark-cli\` | 确保 PATH 先命中 \`~/.local/bin/lark-cli\` |
| 授权页显示错应用 | cwd、\`.env\`、\`LARK_APP_ID\` | 修正目录和 profile 后重新生成授权 URL |
| permission denied | scope、身份、bot 权限 | 先补 bot scope；必须用户语义时再用 user auth |
| 多团队串号 | profile 和 token 共享 | 分 profile，强隔离时分 OS user 或 runtime |
| secret 泄露 | docs/logs/history | 立刻轮换 secret，并清理泄露材料 |

## 9. 安全边界

Agent 必须遵守：

- 不打印 token、secret、cookie、private key、password。
- 不把工具原始输出直接写入长期 memory。
- 不把目标态 Task Bus 当成已交付能力。
- 不把一条渠道消息当成正式任务已接受。
- 不静默绕过 Lark profile wrapper。
- 不把团队业务事实写进全局 memory，除非 owner 批准。
- 不确定时写入 \`needs-review\`，不要自作主张升级为事实。
`;

const llmsTxt = `# openHermit

openHermit is a local AI team operations console.

Primary page: /index.html
Agent-readable Markdown: /agent-manual.md
Repository: https://github.com/yancyuu/Hermit

Use this site for:
- Installation steps
- First team setup
- Agent Loop team operations
- Feishu/Lark CLI team profile isolation
- GitHub Pages troubleshooting

Do not treat this page as source-code documentation. It is an install and operations guide.
`;

const htmlManual = escapeHtml(manual);

const html = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>openHermit 安装与团队运维指南</title>
  <meta name="description" content="openHermit 安装指南与 Agent Loop 团队运维手册。" />
  <meta property="og:title" content="openHermit 安装与团队运维指南" />
  <meta property="og:description" content="面向人和 Agent Loop 的安装、团队运维、飞书隔离与 Pages 排障指南。" />
  <meta property="og:type" content="website" />
  <link rel="icon" href="resources/icons/png/1024x1024.png" />
  <style>
    :root { color-scheme: dark; }
    * { box-sizing: border-box; }
    body {
      margin: 0;
      font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: #09090b;
      color: #e4e4e7;
      line-height: 1.75;
    }
    header, main, footer { max-width: 1120px; margin: 0 auto; padding: 28px; }
    header { border-bottom: 1px solid #27272a; }
    .eyebrow { color: #22c55e; font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
    h1 { margin: 10px 0 12px; font-size: clamp(30px, 5vw, 56px); line-height: 1.05; }
    h2 { margin-top: 36px; padding-top: 24px; border-top: 1px solid #27272a; font-size: 26px; }
    h3 { margin-top: 26px; color: #f4f4f5; }
    .lead { max-width: 850px; color: #a1a1aa; font-size: 17px; }
    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; margin: 22px 0; }
    .card { border: 1px solid #27272a; border-radius: 16px; background: #111113; padding: 18px; }
    .card strong { display: block; margin-bottom: 6px; color: #fafafa; }
    .links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
    a { color: #7dd3fc; }
    .links a { border: 1px solid #3f3f46; border-radius: 999px; padding: 8px 12px; text-decoration: none; color: #e4e4e7; }
    pre, code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; }
    pre {
      overflow-x: auto;
      background: #111113;
      border: 1px solid #27272a;
      border-radius: 14px;
      padding: 16px;
      line-height: 1.55;
    }
    code { color: #bfdbfe; }
    table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 14px; }
    th, td { border: 1px solid #27272a; padding: 10px; vertical-align: top; }
    th { background: #18181b; color: #fafafa; text-align: left; }
    .note { border-left: 4px solid #22c55e; background: #0f1a12; padding: 14px 16px; border-radius: 10px; }
    .manual { white-space: pre-wrap; display: none; }
    footer { color: #71717a; border-top: 1px solid #27272a; }
  </style>
</head>
<body>
  <header>
    <div class="eyebrow">Install Guide · Team Operations · Agent Loop Runbook</div>
    <h1>openHermit 安装与团队运维指南</h1>
    <p class="lead">这份页面只写安装指南和团队运维指南，给人和 Agent Loop 直接照着执行。它不是源码说明，也不展示源码目录。</p>
    <nav class="links" aria-label="Artifacts">
      <a href="agent-manual.md">Agent Markdown</a>
      <a href="llms.txt">llms.txt</a>
      <a href="https://github.com/yancyuu/Hermit/actions/workflows/pages.yml">Pages CI</a>
      <a href="https://github.com/yancyuu/Hermit">GitHub</a>
    </nav>
    <div class="grid">
      <div class="card"><strong>安装入口</strong><span>npm 全局安装后运行 openhermit。</span></div>
      <div class="card"><strong>默认控制台</strong><span>http://127.0.0.1:5680/teams</span></div>
      <div class="card"><strong>团队运维</strong><span>看板、消息、定时 Loop、Agent 状态。</span></div>
      <div class="card"><strong>飞书隔离</strong><span>每个团队独立 LARK_CLI_PROFILE。</span></div>
    </div>
  </header>
  <main>
    <section>
      <h2>1. 快速安装</h2>
      <pre><code>npm install -g @yancyyu/openhermit
openhermit</code></pre>
      <p>启动后打开 <code>http://127.0.0.1:5680</code>，默认进入 <code>/teams</code>。</p>
      <pre><code>openhermit              # 启动
open-hermit             # 等同于 openhermit
hermit                  # 等同于 openhermit
openhermit --port 8080  # 指定端口
openhermit --version    # 查看版本
openhermit update       # 检查并更新</code></pre>
      <div class="note">首次启动会创建 <code>~/.hermit/</code> 目录和 cc-connect 配置。Agent 只能确认文件是否存在，不要打印 token、secret 或 cookie。</div>
    </section>

    <section>
      <h2>2. 本地开发启动</h2>
      <pre><code>git clone https://github.com/yancyuu/Hermit.git
cd Hermit
pnpm install
pnpm dev</code></pre>
      <p>开发地址通常是 <code>http://localhost:5174</code>。项目开发命令使用 <code>pnpm</code>。</p>
    </section>

    <section>
      <h2>3. 创建第一个团队</h2>
      <ol>
        <li>打开 <code>/teams</code>。</li>
        <li>点击「新建团队」。</li>
        <li>填写团队名，例如 frontend、backend、qa、ops。</li>
        <li>选择 harness，例如 claudecode、codex、gemini、qoder。</li>
        <li>绑定 cc-connect project。</li>
        <li>保存后进入团队看板，创建任务或发送消息。</li>
      </ol>
      <table>
        <thead><tr><th>团队</th><th>推荐职责</th><th>推荐 Agent</th></tr></thead>
        <tbody>
          <tr><td>frontend</td><td>UI、交互、前端缺陷</td><td>Claude Code / Qoder</td></tr>
          <tr><td>backend</td><td>API、数据、服务逻辑</td><td>Claude Code / Codex</td></tr>
          <tr><td>qa</td><td>测试、回归、验收</td><td>Gemini / Codex</td></tr>
          <tr><td>ops</td><td>CI、部署、运行状态、排障</td><td>Claude Code</td></tr>
        </tbody>
      </table>
    </section>

    <section>
      <h2>4. 团队运维目录</h2>
      <p>openHermit 自己的团队状态默认放在：</p>
      <pre><code>~/.hermit/teams/&lt;team-slug&gt;/
  team.json
  messages/group.jsonl
  tasks/board.json</code></pre>
      <p>数字员工长期工作区建议按下面组织：</p>
      <pre><code>/Users/distill/teams/
  .memory/rules/
  .memory/decisions/
  .memory/needs-review/
  .claude/skills/
  .claude/workflows/
  &lt;team-folder&gt;/
    .env
    CLAUDE.md
    00_index/conflict-review.md
    01_business-docs/
    03_data/
    07_memory/
    99_temp/</code></pre>
      <table>
        <thead><tr><th>位置</th><th>用途</th><th>不要放</th></tr></thead>
        <tbody>
          <tr><td><code>CLAUDE.md</code></td><td>团队身份、边界、执行规则</td><td>token、secret</td></tr>
          <tr><td><code>07_memory/</code></td><td>经过确认的长期事实</td><td>原始日志、临时输出</td></tr>
          <tr><td><code>needs-review/</code></td><td>冲突事实、待审批提案</td><td>正式事实</td></tr>
          <tr><td><code>skills/</code></td><td>可复用操作能力</td><td>业务密钥</td></tr>
          <tr><td><code>99_temp/</code></td><td>临时材料</td><td>长期规则</td></tr>
        </tbody>
      </table>
    </section>

    <section>
      <h2>5. Agent Loop 运维流程</h2>
      <ol>
        <li>确认当前服务的 team。</li>
        <li>读取 team 的 <code>CLAUDE.md</code> 和必要 <code>07_memory/</code>。</li>
        <li>查询团队任务、消息和最近状态。</li>
        <li>判断输入来自看板、跨团队消息、外部渠道、定时任务还是人工 DM。</li>
        <li>认领任务并更新状态。</li>
        <li>执行最小安全步骤。</li>
        <li>把证据、结果、失败原因写回任务。</li>
        <li>重复动作升级为 skill、workflow 或 cron。</li>
        <li>事实冲突写入 <code>needs-review</code>，停止自动推进。</li>
      </ol>
      <pre><code>received -> in_progress -> completed -> approved
                    └── failed / blocked / needs-review</code></pre>
    </section>

    <section>
      <h2>6. Feishu/Lark CLI 团队隔离</h2>
      <p>每个团队必须有独立 profile。推荐通过 <code>~/.local/bin/lark-cli</code> wrapper 注入 profile。</p>
      <pre><code>Agent 在团队目录调用 lark-cli
  -> PATH 命中 ~/.local/bin/lark-cli
  -> wrapper 向上寻找最近 .env
  -> 读取 LARK_CLI_PROFILE
  -> 调用真实 lark-cli --profile &lt;team-profile&gt;</code></pre>
      <pre><code>LARK_CLI_PROFILE=&lt;team-folder-name&gt;
LARK_CLI_BRAND=feishu
LARK_APP_ID=&lt;app_id&gt;
LARK_APP_SECRET=&lt;app_secret&gt;</code></pre>
      <p>执行飞书操作前检查：</p>
      <pre><code>pwd
command -v lark-cli
lark-cli config show
lark-cli profile list</code></pre>
      <div class="note">App secret 绝不能打印、提交、写日志、写文档或写 memory。</div>
    </section>

    <section>
      <h2>7. Pages 与 CI 排障</h2>
      <ul>
        <li>Pages workflow 名称：<code>Deploy Agent Runbook to GitHub Pages</code>。</li>
        <li>页面由 <code>scripts/build-pages.mjs</code> 生成到 <code>_site/</code>。</li>
        <li>push 到 <code>main</code> 后部署；PR 只 build/verify。</li>
        <li>如果普通 app CI 失败，但 Pages 成功且页面内容正确，不要误判为页面故障。</li>
      </ul>
      <p>线上页面必须包含：</p>
      <pre><code>openHermit 安装与团队运维指南
Feishu/Lark CLI 团队隔离</code></pre>
    </section>

    <section>
      <h2>8. 安全边界</h2>
      <ul>
        <li>不打印 token、secret、cookie、private key、password。</li>
        <li>不把原始工具输出直接写入长期 memory。</li>
        <li>不把渠道消息当作正式任务已接受。</li>
        <li>不静默绕过 Lark profile wrapper。</li>
        <li>不确定时写入 <code>needs-review</code>，不要自作主张变成事实。</li>
      </ul>
    </section>
    <pre class="manual">${htmlManual}</pre>
  </main>
  <footer>
    Generated by scripts/build-pages.mjs. This page is an installation and operations guide, not source-code documentation.
  </footer>
</body>
</html>
`;

rmSync(OUT_DIR, { recursive: true, force: true });
mkdirSync(OUT_DIR, { recursive: true });
writeText('agent-manual.md', manual);
writeText('llms.txt', llmsTxt);
writeText('index.html', html);
copyIfExists('resources/icons');

console.log(`Built GitHub Pages site at ${OUT_DIR}`);
console.log('- index.html');
console.log('- agent-manual.md');
console.log('- llms.txt');
