chore: add codex workspace hooks
This commit is contained in:
23
.codex/config.toml
Normal file
23
.codex/config.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
# Genarrative 项目级 Codex 配置。
|
||||
# 这里仅保存可进入仓库的 hook 配置与脚本;个人 token、MCP server、模型路由仍放在个人 ~/.codex/config.toml。
|
||||
|
||||
[features]
|
||||
hooks = true
|
||||
|
||||
# Codex 准备执行 git commit 前检查 TypeScript / admin-web / api-server 编译错误。
|
||||
# 脚本也可手动运行:
|
||||
# node .codex/hooks/pre-submit-compile-check.mjs
|
||||
[[hooks.PreToolUse]]
|
||||
matcher = "Bash|shell_command|functions.shell_command"
|
||||
command = "node .codex/hooks/pre-submit-compile-check.mjs"
|
||||
timeout = 180
|
||||
statusMessage = "提交前检查编译错误"
|
||||
|
||||
# Codex 每次工具修改文件后执行:同步 CodeGraph 索引。
|
||||
# 脚本也可手动运行:
|
||||
# node .codex/hooks/post-edit-codegraph-sync.mjs
|
||||
[[hooks.PostToolUse]]
|
||||
matcher = "Bash|Edit|MultiEdit|Write|apply_patch|shell_command|functions.shell_command|functions.apply_patch"
|
||||
command = "node .codex/hooks/post-edit-codegraph-sync.mjs"
|
||||
timeout = 60
|
||||
statusMessage = "更新 CodeGraph 索引"
|
||||
51
.codex/hooks/post-edit-codegraph-sync.mjs
Normal file
51
.codex/hooks/post-edit-codegraph-sync.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(scriptDir, '..', '..');
|
||||
const logDir = resolve(repoRoot, '.codex', 'logs');
|
||||
const hasCodegraphConfig = existsSync(resolve(repoRoot, '.codegraph', 'config.json'));
|
||||
const npmCommand = process.platform === 'win32' ? 'cmd' : 'npm';
|
||||
|
||||
if (!hasCodegraphConfig) {
|
||||
console.log('[codex-hook] 未发现 .codegraph/config.json,跳过 CodeGraph 同步。');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const result = spawnSync(npmCommand, process.platform === 'win32' ? ['/d', '/s', '/c', 'npm run codegraph:sync'] : ['run', 'codegraph:sync'], {
|
||||
cwd: repoRoot,
|
||||
shell: false,
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
NO_COLOR: process.env.NO_COLOR ?? '1',
|
||||
},
|
||||
});
|
||||
|
||||
mkdirSync(logDir, { recursive: true });
|
||||
if (result.stdout) {
|
||||
process.stdout.write(result.stdout);
|
||||
}
|
||||
if (result.stderr) {
|
||||
process.stderr.write(result.stderr);
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
console.error(`[codex-hook] CodeGraph 同步启动失败:${result.error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (result.signal) {
|
||||
console.error(`[codex-hook] CodeGraph 同步被信号终止:${result.signal}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if ((result.status ?? 0) !== 0) {
|
||||
console.error('[codex-hook] CodeGraph 同步失败,请手动运行 npm run codegraph:sync 查看详情。');
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
|
||||
console.log('[codex-hook] CodeGraph 已同步。');
|
||||
122
.codex/hooks/pre-submit-compile-check.mjs
Normal file
122
.codex/hooks/pre-submit-compile-check.mjs
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(scriptDir, '..', '..');
|
||||
const npmCommand = process.platform === 'win32' ? 'cmd' : 'npm';
|
||||
const hookInput = readHookInput();
|
||||
|
||||
if (hookInput && !isGitCommitCommand(extractShellCommand(hookInput))) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const validationSteps = [
|
||||
{
|
||||
label: 'TypeScript typecheck',
|
||||
command: npmCommand,
|
||||
args: process.platform === 'win32' ? ['/d', '/s', '/c', 'npm run typecheck'] : ['run', 'typecheck'],
|
||||
},
|
||||
{
|
||||
label: 'Admin web typecheck',
|
||||
command: npmCommand,
|
||||
args: process.platform === 'win32' ? ['/d', '/s', '/c', 'npm run admin-web:typecheck'] : ['run', 'admin-web:typecheck'],
|
||||
},
|
||||
{
|
||||
label: 'Rust api-server compile check',
|
||||
command: 'cargo',
|
||||
args: ['check', '-p', 'api-server', '--manifest-path', 'server-rs/Cargo.toml'],
|
||||
},
|
||||
];
|
||||
|
||||
for (const step of validationSteps) {
|
||||
const result = runStep(step);
|
||||
if (!result.ok) {
|
||||
const reason = `[codex-hook] 提交前编译检查失败:${step.label}。请修复编译错误后再提交。`;
|
||||
console.error(reason);
|
||||
if (hookInput) {
|
||||
console.log(JSON.stringify({ decision: 'block', reason }));
|
||||
process.exit(0);
|
||||
}
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
}
|
||||
|
||||
console.error('[codex-hook] 提交前编译检查通过。');
|
||||
|
||||
function runStep(step) {
|
||||
console.error(`[codex-hook] ${step.label}`);
|
||||
const result = spawnSync(step.command, step.args, {
|
||||
cwd: repoRoot,
|
||||
shell: false,
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
NO_COLOR: process.env.NO_COLOR ?? '1',
|
||||
},
|
||||
});
|
||||
|
||||
if (result.stdout) {
|
||||
process.stderr.write(result.stdout);
|
||||
}
|
||||
if (result.stderr) {
|
||||
process.stderr.write(result.stderr);
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
console.error(`[codex-hook] ${step.label} 启动失败:${result.error.message}`);
|
||||
return { ok: false, status: 1 };
|
||||
}
|
||||
|
||||
if (result.signal) {
|
||||
console.error(`[codex-hook] ${step.label} 被信号终止:${result.signal}`);
|
||||
return { ok: false, status: 1 };
|
||||
}
|
||||
|
||||
return {
|
||||
ok: (result.status ?? 0) === 0,
|
||||
status: result.status ?? 1,
|
||||
};
|
||||
}
|
||||
|
||||
function readHookInput() {
|
||||
try {
|
||||
const rawInput = readFileSync(0, 'utf8').trim();
|
||||
if (!rawInput) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(rawInput);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function extractShellCommand(input) {
|
||||
const candidates = [
|
||||
input?.tool_input?.command,
|
||||
input?.toolInput?.command,
|
||||
input?.tool_args?.command,
|
||||
input?.toolArgs?.command,
|
||||
input?.arguments?.command,
|
||||
input?.params?.command,
|
||||
input?.command,
|
||||
];
|
||||
|
||||
const command = candidates.find(value => typeof value === 'string' && value.trim().length > 0);
|
||||
if (command) {
|
||||
return command;
|
||||
}
|
||||
|
||||
const shellCommand = input?.tool_input?.cmd ?? input?.toolInput?.cmd ?? input?.arguments?.cmd;
|
||||
if (Array.isArray(shellCommand)) {
|
||||
return shellCommand.join(' ');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function isGitCommitCommand(command) {
|
||||
return /(^|[;&|]\s*)git(?:\.exe)?\b[\s\S]{0,200}\bcommit\b/iu.test(command);
|
||||
}
|
||||
@@ -121,7 +121,14 @@ npm run codegraph:sync
|
||||
npm run codegraph:index
|
||||
```
|
||||
|
||||
`.codegraph/config.json` 可随仓库共享;`.codegraph/codegraph.db`、缓存和日志为本机生成物,不提交。Codex CLI / Cursor / Claude Code 等 MCP 客户端配置属于个人环境;需要时由成员本机执行 `codegraph install` 或查看 `codegraph install --print-config codex`,不要提交个人全局配置。
|
||||
`.codegraph/config.json` 可随仓库共享;`.codegraph/codegraph.db`、缓存和日志为本机生成物,不提交。
|
||||
|
||||
Codex 项目级 hook 保存在 `.codex/config.toml` 与 `.codex/hooks/`:
|
||||
|
||||
- `PreToolUse` hook:`node .codex/hooks/pre-submit-compile-check.mjs`,Codex 准备执行 `git commit` 前检查 `npm run typecheck`、`npm run admin-web:typecheck`、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
- `PostToolUse` hook:`node .codex/hooks/post-edit-codegraph-sync.mjs`,工具修改文件后执行 `npm run codegraph:sync`。
|
||||
|
||||
个人 token、模型路由、MCP server 仍属于个人环境;需要时由成员本机执行 `codegraph install` 或查看 `codegraph install --print-config codex`,不要提交个人全局配置。
|
||||
|
||||
## 常用检查命令
|
||||
|
||||
|
||||
@@ -113,7 +113,13 @@ npm run codegraph:sync
|
||||
npm run codegraph:index
|
||||
```
|
||||
|
||||
若要把 CodeGraph 接到 Codex CLI / Cursor / Claude Code 等 MCP 客户端,按本机 agent 配置执行 `codegraph install` 或参考 `codegraph install --print-config codex` 输出;不要把个人全局 agent 配置、token 或本机绝对路径提交到仓库。Codex CLI 当前没有项目级 MCP 配置,需由使用者在个人 `~/.codex/config.toml` 中配置。
|
||||
Codex 项目级 hook 已放在 `.codex/config.toml` 与 `.codex/hooks/`:
|
||||
|
||||
- `PreToolUse` hook 会在 Codex 准备执行 `git commit` 前运行 `node .codex/hooks/pre-submit-compile-check.mjs`,依次执行 `npm run typecheck`、`npm run admin-web:typecheck`、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`,发现编译错误会阻止本次提交。
|
||||
- `PostToolUse` hook 会在 Codex 工具修改文件后运行 `node .codex/hooks/post-edit-codegraph-sync.mjs`,执行 `npm run codegraph:sync` 刷新本地语义索引。
|
||||
- 如果某个 Codex 客户端版本尚未自动加载项目级 hook,可先手动运行 `node .codex/hooks/pre-submit-compile-check.mjs` 与 `node .codex/hooks/post-edit-codegraph-sync.mjs`;个人模型、token、MCP server 仍放在个人 `~/.codex/config.toml`,不要提交。
|
||||
|
||||
若要把 CodeGraph 接到 Codex CLI / Cursor / Claude Code 等 MCP 客户端,按本机 agent 配置执行 `codegraph install` 或参考 `codegraph install --print-config codex` 输出;不要把个人全局 agent 配置、token 或本机绝对路径提交到仓库。
|
||||
|
||||
## 后端改动验收
|
||||
|
||||
|
||||
Reference in New Issue
Block a user