Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [20, 22]
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.9"

- name: Install dependencies
run: bun install

- name: Run tests
run: bun run test

- name: CI end-to-end verify
run: bun run ci:verify
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- `tests/`:Node 内置测试(`*.test.js`),覆盖 CLI、适配器、生成器、清理与健康检查。
- `docs/` 与 `reference/`:规范文档与参考资料。
- `web/`:Next.js 文档站(`web/src` 源码,`web/public` 静态资源)。
- `.agent/`:模板资源源文件,供 CLI 安装到目标项目
- `.agents/`:模板资源源文件(Canonical),供 CLI 投影生成目标项目结构(Gemini -> `.agent/`,Codex -> `.agents/`)

## 构建、测试与开发命令
- 根项目依赖安装:`bun install`(如需兼容可用 `npm install`)。
Expand Down
56 changes: 49 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
npm install -g @mison/ag-kit-cn
```

或使用 Bun:

```bash
bun install -g @mison/ag-kit-cn
```

然后在你的目标项目中初始化:

```bash
Expand All @@ -41,12 +47,37 @@ npm install -g .

这会把所选目标结构安装到你的项目中(`gemini -> .agent`,`codex -> .agents`),并把 Codex 托管内容注入工作区 `AGENTS.md` 与 `antigravity.rules`(说明性托管区块,不是 Codex 官方 `.rules` 审批策略文件)。

### 全局安装(跨项目复用 Skills)

为区分“项目安装”和“全局安装”,提供专用命令面:

- 项目安装:`ag-kit init` / `ag-kit update`(功能最完整)
- 全局安装:`ag-kit global sync`(仅同步 Skills,跨项目复用)
- 默认行为:`ag-kit global sync` 未指定 `--target/--targets` 时,同步 `codex + gemini`
- 真实落盘:
- `codex` -> `~/.codex/skills/`
- `gemini` -> 同时写入 `~/.gemini/skills/` 与 `~/.gemini/antigravity/skills/`

示例:

```bash
ag-kit global sync
ag-kit global sync --target codex
ag-kit global sync --target gemini
ag-kit global status
```

全局安装只同步 Skills,不写入 Rules/Agents/Workflows,避免全局副作用。
覆盖同名 Skill 前会自动备份;手动回滚方式见 `docs/TECH.md`。

规划与边界细节见:`docs/PLAN.md`(规划)与 `docs/TECH.md`(技术)。

### Codex 规则边界说明

- `antigravity.rules`:本项目生成并注入的托管说明文件,用于记录受管资源与运维约束。
- `.rules`(如 `~/.codex/rules/default.rules`):Codex 官方的命令审批/执行策略文件(Starlark 规则,支持 `prefix_rule()`)。
- 默认行为:本项目不会自动写入你的全局 `~/.codex/rules`,避免引入不可预期的全局副作用。
- 如需启用官方 `.rules` 审批策略,请参考 `docs/codex-rules-template.md`。
- 如需启用官方 `.rules` 审批策略,请参考 `docs/TECH.md` 的「Codex 官方 `.rules`(手动配置)」小节

### ⚠️ 关于 `.gitignore` 的重要说明

Expand Down Expand Up @@ -137,6 +168,8 @@ CLI(命令行界面)工具:
| `ag-kit update` | 更新当前项目已安装目标 |
| `ag-kit update-all` | 批量更新所有已登记工作区 |
| `ag-kit doctor` | 诊断安装完整性(可 `--fix` 自愈) |
| `ag-kit global sync` | 全局同步 Skills(默认同步 codex + gemini;其中 gemini 同步到 gemini-cli 与 antigravity) |
| `ag-kit global status` | 查看全局 Skills 安装状态 |
| `ag-kit exclude` | 管理全局索引排除清单 |
| `ag-kit status` | 检查安装状态 |

Expand All @@ -160,6 +193,13 @@ ag-kit exclude add --path /path/to/dir # 新增排除路径
ag-kit exclude remove --path /path/to/dir # 删除排除路径
```

### 状态命令约定

- `ag-kit status --quiet`:输出 `installed` / `broken` / `missing`
- `ag-kit global status --quiet`:输出 `installed` / `broken` / `missing`
- 退出码:`0=installed`,`1=broken`,`2=missing`
- `status` 面向自动化健康判断;如需问题明细,使用 `ag-kit doctor`

### 批量更新机制

- 执行 `ag-kit init` / `ag-kit update` 时,会把工作区路径登记到全局索引文件:
Expand All @@ -177,19 +217,21 @@ ag-kit exclude remove --path /path/to/dir # 删除排除路径
### 开发维护命令

```bash
npm run clean # 清理本地生成产物(如 web/.next、web/node_modules)
npm run clean:dry-run # 预览将被清理的路径
npm test # 只执行 tests/ 目录下测试
npm run health-check # 一键执行全链路健康复检
bun run clean # 清理本地生成产物(如 web/.next、web/node_modules)
bun run clean:dry-run # 预览将被清理的路径
bun run test # 只执行 tests/ 目录下测试
bun run health-check # 一键执行全链路健康复检
```

如果你在 `web/` 子项目内开发,可按需执行:

```bash
npm install --prefix web
npm run lint --prefix web
bun install --cwd web
bun run lint --cwd web
```

> 说明:若你通过 `bun install -g` 安装 CLI,Bun 默认会阻止本包 `postinstall`。上游同名包冲突提示会在首次执行 `ag-kit init/update/update-all/global sync` 时给出。

## 卸载

### 卸载本机全局 CLI
Expand Down
30 changes: 24 additions & 6 deletions bin/adapters/codex.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,17 @@ class CodexAdapter extends BaseAdapter {
const CodexBuilder = require("../core/builder");
let buildTemp = "";

const hasAgentDir = fs.existsSync(path.join(installSource, ".agent"));
const hasAgentsRoot = fs.existsSync(path.join(installSource, ".agents"));
const hasLegacyAgentRoot = fs.existsSync(path.join(installSource, ".agent"));
const hasSkillsDir = fs.existsSync(path.join(installSource, "skills"));
const isCodexPrebuilt = fs.existsSync(path.join(installSource, "manifest.json"));

if (!isCodexPrebuilt) {
if (hasSkillsDir) {
this.log("🛠️ 检测到 .agent 内容格式,正在构建 Codex 结构...");
this.log("🛠️ 检测到模板目录格式,正在构建 Codex 结构...");
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-root-"));
const mockAgent = path.join(mockRoot, ".agent");
this._copyDir(installSource, mockAgent);
const mockAgents = path.join(mockRoot, ".agents");
this._copyDir(installSource, mockAgents);

buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
CodexBuilder.build(mockRoot, buildTemp);
Expand All @@ -154,8 +155,8 @@ class CodexAdapter extends BaseAdapter {
fs.rmSync(mockRoot, { recursive: true, force: true });
fs.rmSync(buildTemp, { recursive: true, force: true });
};
} else if (hasAgentDir) {
this.log("🛠️ 检测到仓库根目录格式,正在构建 Codex 结构...");
} else if (hasAgentsRoot) {
this.log("🛠️ 检测到仓库根目录格式(.agents),正在构建 Codex 结构...");
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
CodexBuilder.build(installSource, buildTemp);
installSource = buildTemp;
Expand All @@ -166,6 +167,23 @@ class CodexAdapter extends BaseAdapter {
if (previousCleanup) previousCleanup();
fs.rmSync(buildTemp, { recursive: true, force: true });
};
} else if (hasLegacyAgentRoot) {
this.log("🛠️ 检测到旧版仓库根目录格式(.agent),正在构建 Codex 结构...");
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-root-"));
const mockAgents = path.join(mockRoot, ".agents");
this._copyDir(path.join(installSource, ".agent"), mockAgents);

buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
CodexBuilder.build(mockRoot, buildTemp);
installSource = buildTemp;
sourceLabel = `${sourceLabel}:compiled`;

const previousCleanup = cleanup;
cleanup = () => {
if (previousCleanup) previousCleanup();
fs.rmSync(mockRoot, { recursive: true, force: true });
fs.rmSync(buildTemp, { recursive: true, force: true });
};
}
}

Expand Down
4 changes: 1 addition & 3 deletions bin/adapters/gemini.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ class GeminiAdapter extends BaseAdapter {
}

getInstalledVersion() {
// In v1, version was not strictly tracked per target in a file.
// We assume check existence of .agent/agents directory.
const agentDir = path.join(this.workspaceRoot, ".agent");
if (fs.existsSync(agentDir)) {
return "2.0.1"; // Default to current version if exists
return null;
}
return null;
}
Expand Down
Loading
Loading