Skip to content

Commit de0936a

Browse files
authored
Add locked Rust runtime candidate for CodeGuard plugin (#85)
* feat: add locked Rust runtime candidate for plugin * fix: reject nonregular runtime archive members
1 parent 0d7d9ea commit de0936a

19 files changed

Lines changed: 654 additions & 9 deletions

‎.agents/plugins/marketplace.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
"source": {
1010
"source": "url",
1111
"url": "https://github.com/full-stack-plugins/codeguard-plugin.git",
12-
"ref": "v0.16.1"
12+
"ref": "v0.17.0"
1313
},
1414
"policy": {
1515
"installation": "AVAILABLE",
1616
"authentication": "ON_USE"
1717
},
1818
"category": "Developer Tools",
19-
"version": "0.16.1",
19+
"version": "0.17.0",
2020
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
21-
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.16.1/assets/official-logo.png",
21+
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.17.0/assets/official-logo.png",
2222
"interface": {
2323
"displayName": "代码规范守卫",
2424
"shortDescription": "Trustworthy code checks and Java impact analysis",
25-
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.16.1/assets/official-logo.png"
25+
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.17.0/assets/official-logo.png"
2626
}
2727
}
2828
]

‎.claude-plugin/marketplace.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"name": "codeguard",
99
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
10-
"version": "0.16.1",
10+
"version": "0.17.0",
1111
"source": "./"
1212
}
1313
]

‎.codex-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeguard",
3-
"version": "0.16.1+codex.20260924",
3+
"version": "0.17.0+codex.20260929",
44
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
55
"author": {
66
"name": "Full Stack Skills / PartMe.AI",

‎.github/workflows/skills-check.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ on:
66
branches: [main]
77

88
jobs:
9+
rust-runtime-contract:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
13+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
14+
with:
15+
node-version: "24"
16+
package-manager-cache: false
17+
- name: Check candidate runtime syntax and fail-incomplete behavior
18+
run: |
19+
node --check runtime/codeguard_runtime.cjs
20+
node --check hooks/rust_runtime_dispatch.cjs
21+
node --test tests/test_rust_runtime.cjs
922
vendor-check:
1023
runs-on: ubuntu-latest
1124
strategy:

‎.zcode-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"en": "代码规范守卫",
66
"zh-CN": "代码规范检查"
77
},
8-
"version": "0.16.1",
8+
"version": "0.17.0",
99
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
1010
"description_i18n": {
1111
"en": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",

‎README.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010

1111
CodeGuard provides native check evidence and guards supported Git commit/push calls from AI coding assistants. PostToolUse gives feedback, not blocking. Verified violations block the Git call; unavailable checks remain explicitly UNVERIFIED. Passing a configured check is not proof of complete code correctness.
1212

13+
### Rust runtime candidate (macOS arm64)
14+
15+
The plugin now contains a **candidate**, explicit Rust runtime binding. It pins `@partme.ai/codeguard@0.1.1`, its registry tarball and native binary hashes, candidate source commit, platform, and check protocol major in [`runtime/codeguard.lock.json`](runtime/codeguard.lock.json). Install only on Apple Silicon macOS:
16+
17+
```bash
18+
node runtime/codeguard_runtime.cjs install --download
19+
node runtime/codeguard_runtime.cjs verify
20+
```
21+
22+
For offline installation, use `install --tarball /absolute/path/to/partme.ai-codeguard-0.1.1.tgz`; the same lock hashes are enforced. Installation stages and verifies the package before switching the active receipt. [`hooks/rust_runtime_dispatch.cjs`](hooks/rust_runtime_dispatch.cjs) is a candidate Claude Code adapter for SessionStart, PostToolUse, PostToolUseFailure, and Stop. It rechecks the active binary before each call, never selects a random `codeguard` on `PATH`, and reports an incomplete runtime instead of falling back to Python. The current [`hooks/hooks.json`](hooks/hooks.json) still uses the legacy Python hooks; the Rust candidate has not been made the default, connected to a strict Git gate, or accepted on Codex/ZCode/Kimi. See the [candidate acceptance record](tests/rust-runtime-candidate.md) and [hook protocol](hooks/__protocol__.md).
23+
1324
The installed plugin version is recorded in its manifests. The architecture refactor keeps the existing 68 managed skills and focuses on reliable evidence, clear module ownership and Java project awareness.
1425

1526
### Runtime boundaries

‎README.zh-CN.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010

1111
CodeGuard 为 AI 编程助手提供原生检查证据,守护已支持的 Git 提交/推送调用。PostToolUse 只反馈、不阻断;确定违规会拦截 Git 调用;检查无法完成时明确 UNVERIFIED。某项检查通过,不等于代码完全正确。
1212

13+
### Rust 运行时候选(macOS arm64)
14+
15+
插件新增**显式候选** Rust 运行时绑定。[`runtime/codeguard.lock.json`](runtime/codeguard.lock.json) 固定 `@partme.ai/codeguard@0.1.1`、注册表 tarball 和原生二进制摘要、候选源码提交、平台及检查协议主版本。仅在 Apple Silicon macOS 上安装:
16+
17+
```bash
18+
node runtime/codeguard_runtime.cjs install --download
19+
node runtime/codeguard_runtime.cjs verify
20+
```
21+
22+
离线安装可执行 `install --tarball /absolute/path/to/partme.ai-codeguard-0.1.1.tgz`,仍须满足同一锁定摘要。安装器先在暂存目录核验包,再切换活动收据。[`hooks/rust_runtime_dispatch.cjs`](hooks/rust_runtime_dispatch.cjs) 是 Claude Code 的 SessionStart、PostToolUse、PostToolUseFailure、Stop 候选适配器;每次调用前复核活动二进制,不从 PATH 随机选择 `codeguard`,缺运行时时报告未完成而不回退 Python。当前 [`hooks/hooks.json`](hooks/hooks.json) 仍使用旧 Python 钩子;Rust 候选尚未成为默认入口,未接严格 Git 门禁,也未在 Codex/ZCode/Kimi 完成宿主验收。见[候选验收记录](tests/rust-runtime-candidate.md)和[钩子协议](hooks/__protocol__.md)。
23+
1324
已安装插件的版本以各清单为准。本次架构重构保留现有 68 个受管技能,重点收敛判定证据、模块职责与 Java 项目感知。
1425

1526
### 运行边界

‎com.github.copilot/hooks/__protocol__.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# hooks/ 与宿主 CLI 之间的契约(canonical cheat-sheet)
22

3+
> Rust 候选入口:`runtime/codeguard_runtime.cjs` 固定 npm 0.1.1 制品和本机二进制身份;`hooks/rust_runtime_dispatch.cjs` 显式处理 Claude Code 的 SessionStart/PostToolUse/PostToolUseFailure/Stop。候选入口在运行时缺失、摘要或版本失配时返回对话中的“未完成”,不执行 PATH 上的 `codeguard`,也不回退到 Python。它尚未写入 `hooks/hooks.json`,以下旧协议表仍描述默认 Python 运行时。Rust 严格交付门禁与其它宿主接线尚未完成,不能把候选保存反馈当作通过。
4+
35
> 这份文档是 codeguard-plugin 与 Codex CLI / ZCode / Kimi Code 三端宿主
46
> 交互契约的**单源事实**。所有 hook 脚本(`hooks/*.py`)的实现都必须与本文件
57
> 一致;若未来调整任何退出码或 JSON schema,**同一 commit 内**必须更新本文件。
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
4+
// Candidate Claude Code binding. It never resolves `codeguard` from PATH or falls back to Python.
5+
const fs = require('node:fs');
6+
const path = require('node:path');
7+
const { spawnSync } = require('node:child_process');
8+
const pluginRoot = fs.existsSync(path.join(__dirname, '..', 'runtime', 'codeguard_runtime.cjs'))
9+
? path.resolve(__dirname, '..') : path.resolve(__dirname, '..', '..');
10+
const { activeBinary } = require(path.join(pluginRoot, 'runtime', 'codeguard_runtime.cjs'));
11+
12+
const EVENTS = new Map([
13+
['session-start', 'SessionStart'],
14+
['post-tool-use', 'PostToolUse'],
15+
['post-tool-use-failure', 'PostToolUseFailure'],
16+
['stop', 'Stop'],
17+
]);
18+
19+
function incomplete(event, reason) {
20+
const safe = /^[a-z_]+$/.test(reason) ? reason : 'runtime_unavailable';
21+
const message = `CodeGuard Rust 运行时未完成(${safe});本次源码检查未运行,交付未评估。请执行插件 runtime/codeguard_runtime.cjs verify 或修复安装。`;
22+
return event === 'stop'
23+
? { systemMessage: message }
24+
: { hookSpecificOutput: { hookEventName: EVENTS.get(event), additionalContext: message } };
25+
}
26+
27+
function readInput() {
28+
const pieces = [];
29+
const buffer = Buffer.allocUnsafe(64 * 1024);
30+
let total = 0;
31+
for (;;) {
32+
const length = fs.readSync(0, buffer, 0, buffer.length, null);
33+
if (length === 0) break;
34+
total += length;
35+
if (total > 1024 * 1024) throw new Error('host_input_too_large');
36+
pieces.push(Buffer.from(buffer.subarray(0, length)));
37+
}
38+
return Buffer.concat(pieces);
39+
}
40+
41+
function projectRoot() {
42+
const configured = process.env.CLAUDE_PROJECT_DIR;
43+
const value = configured && path.isAbsolute(configured) ? configured : process.cwd();
44+
return fs.realpathSync(value);
45+
}
46+
47+
function run(event) {
48+
if (!EVENTS.has(event)) throw new Error('event_unsupported');
49+
const input = readInput();
50+
const binary = activeBinary();
51+
const root = projectRoot();
52+
const result = spawnSync(binary, ['hook', 'claude', event, root, '--timeout=5s', '--format=json'], {
53+
input, encoding: 'utf8', shell: false, timeout: 8000, maxBuffer: 16 * 1024,
54+
env: process.env,
55+
});
56+
if (result.error || result.signal || result.status !== 0) throw new Error('runtime_execution_failed');
57+
let output;
58+
try { output = JSON.parse(result.stdout); } catch { throw new Error('runtime_response_invalid'); }
59+
if (event === 'stop') {
60+
if (typeof output.systemMessage !== 'string'
61+
&& output.hookSpecificOutput?.hookEventName !== 'Stop') {
62+
throw new Error('runtime_response_invalid');
63+
}
64+
} else if (output.hookSpecificOutput?.hookEventName !== EVENTS.get(event)
65+
|| typeof output.hookSpecificOutput.additionalContext !== 'string') {
66+
throw new Error('runtime_response_invalid');
67+
}
68+
return output;
69+
}
70+
71+
if (require.main === module) {
72+
const event = process.argv[2];
73+
try {
74+
process.stdout.write(JSON.stringify(run(event)) + '\n');
75+
} catch (error) {
76+
const reason = typeof error.message === 'string' && error.message.startsWith('codeguard runtime incomplete: ')
77+
? error.message.slice('codeguard runtime incomplete: '.length)
78+
: error.message;
79+
if (EVENTS.has(event)) process.stdout.write(JSON.stringify(incomplete(event, reason)) + '\n');
80+
else {
81+
process.stderr.write('CodeGuard Rust 宿主事件无效。\n');
82+
process.exitCode = 2;
83+
}
84+
}
85+
}
86+
87+
module.exports = { run };

‎dev.openhands/hooks/__protocol__.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# hooks/ 与宿主 CLI 之间的契约(canonical cheat-sheet)
22

3+
> Rust 候选入口:`runtime/codeguard_runtime.cjs` 固定 npm 0.1.1 制品和本机二进制身份;`hooks/rust_runtime_dispatch.cjs` 显式处理 Claude Code 的 SessionStart/PostToolUse/PostToolUseFailure/Stop。候选入口在运行时缺失、摘要或版本失配时返回对话中的“未完成”,不执行 PATH 上的 `codeguard`,也不回退到 Python。它尚未写入 `hooks/hooks.json`,以下旧协议表仍描述默认 Python 运行时。Rust 严格交付门禁与其它宿主接线尚未完成,不能把候选保存反馈当作通过。
4+
35
> 这份文档是 codeguard-plugin 与 Codex CLI / ZCode / Kimi Code 三端宿主
46
> 交互契约的**单源事实**。所有 hook 脚本(`hooks/*.py`)的实现都必须与本文件
57
> 一致;若未来调整任何退出码或 JSON schema,**同一 commit 内**必须更新本文件。

0 commit comments

Comments
 (0)