Skip to content

Commit 30e7237

Browse files
authored
Merge pull request #17 from full-stack-plugins/feat/rust-hook-prompt-guidance
Python 缺少 Ruff 时提供有界 WASM 语法候选反馈
2 parents 06ab734 + cbc5385 commit 30e7237

22 files changed

Lines changed: 1320 additions & 26 deletions

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli
9494

9595
Version output includes `cli_version`, `target`, and protocol information. Discovery and init preview return observations and unknowns. Dry-run creates neither `AGENTS.md` nor a project data directory. Add Cargo `--offline` only when dependencies are cached.
9696

97-
The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with pinned Java, TypeScript, and TSX grammar candidates. It currently reaches only single-file `lint java` and `lint typescript` requests without explicit native context; `.tsx` uses its own grammar. It is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed.
97+
The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with pinned Java, Python, TypeScript, and TSX grammar candidates. Java and TypeScript/TSX have narrow single-file fallback paths; `lint python` can provide bounded suspected syntax positions when Ruff is unavailable or no project Ruff configuration is declared. Native Ruff results take priority. It is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed.
9898

99-
The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has four unqualified asset candidates (Java, Python, TypeScript, TSX) and zero released syntax capabilities. Python is pinned and Rust-loadable but has no CLI fallback path. The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB source asset also exceeds the current Rust loader's 8 MiB limit.
99+
The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has four unqualified asset candidates (Java, Python, TypeScript, TSX) and zero released syntax capabilities. Python has a source-build-only, unqualified CLI fallback path; its report remains incomplete and cannot approve delivery. The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB source asset also exceeds the current Rust loader's 8 MiB limit.
100100

101101
### npm installation and one-off use
102102

@@ -181,7 +181,7 @@ Generic `dependencies`, generic `security`, arbitrary category/language combinat
181181

182182
**The published `0.1.2` does not yet implement bundled WASM fallback or automatic conversation delivery.** The existing commands remain the unified entry points; native adapter-specific prerequisites still apply today:
183183

184-
An opt-in source build with `--features codeguard-cli/wasm-precheck` has narrow TypeScript and Java single-file candidate paths. For TypeScript, a visible local ESLint 10 entry and one flat config take priority: when an executable Node is resolved from `PATH`, the CLI runs its existing bounded native probe; without Node it reports the setup gap. Only when the project-local ESLint package is not observed can the bundled TypeScript/TSX candidate provide suspected syntax positions; an untrusted entry, package identity or config returns a specific setup blocker. The Java candidate likewise remains incomplete; no bundled grammar has an accepted language/dialect range. Native observations and prechecks never approve delivery. Default and published binaries keep their previous native-context behavior. [TypeScript acceptance](tests/acceptance/typescript-syntax-fallback-candidate.md) · [native-first acceptance](tests/acceptance/native-first-eslint-candidate.md) · [Java acceptance](tests/acceptance/java-syntax-fallback-candidate.md).
184+
An opt-in source build with `--features codeguard-cli/wasm-precheck` has narrow TypeScript and Java single-file candidate paths. For TypeScript, a visible local ESLint 10 entry and one flat config take priority: when an executable Node is resolved from `PATH`, the CLI runs its existing bounded native probe; without Node it reports the setup gap. Only when the project-local ESLint package is not observed can the bundled TypeScript/TSX candidate provide suspected syntax positions; an untrusted entry, package identity or config returns a specific setup blocker. The Java candidate likewise remains incomplete. Python `lint` first preserves Ruff results, then can attach suspected positions for missing Ruff or undeclared project Ruff configuration; a broken Ruff configuration stays a setup blocker. No bundled grammar has an accepted language/dialect range. Native observations and prechecks never approve delivery. Default and published binaries keep their previous native-context behavior. [TypeScript acceptance](tests/acceptance/typescript-syntax-fallback-candidate.md) · [native-first acceptance](tests/acceptance/native-first-eslint-candidate.md) · [Java acceptance](tests/acceptance/java-syntax-fallback-candidate.md).
185185

186186
With an initialized `--workspace`, that TypeScript/TSX fallback now returns a real, stable native-confirmation task ID after sync; repeated WASM scans never close it. A versioned local report now preserves bounded suspected positions with source and grammar identities; capability-matched native closure still needs implementation. [Workbench acceptance](tests/acceptance/typescript-syntax-confirmation-task.md).
187187

‎README.zh-CN.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli
9494

9595
版本输出包含 `cli_version`、`target` 和协议信息。发现与 init 预览返回观察及未知项。Dry-run 不创建 `AGENTS.md` 或项目数据目录。仅在依赖已缓存时为 Cargo 添加 `--offline`。
9696

97-
工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java、TypeScript、TSX grammar 候选资产与有界 Rust worker,为缺少显式原生上下文的 `lint java`、`lint typescript` 单文件请求提供疑似语法观察;`.tsx` 使用独立 grammar。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。
97+
工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java、Python、TypeScript、TSX grammar 候选资产与有界 Rust worker。Java 和 TypeScript/TSX 有局部单文件兜底;`lint python` 在 Ruff 不可用或项目未声明 Ruff 配置时可报告有界疑似语法位置,原生 Ruff 结果优先。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。
9898

99-
当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前有 Java、Python、TypeScript、TSX 四份未验收资产候选,已发行语法能力为零。Python 已固定并通过 Rust 加载试验,但尚未接入 CLI 兜底。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。
99+
当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前有 Java、Python、TypeScript、TSX 四份未验收资产候选,已发行语法能力为零。Python 已有仅限源码可选构建的 CLI 候选兜底,结果保持不完整,不能批准交付。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。
100100

101101
### npm 安装与一次性调用
102102

@@ -180,7 +180,7 @@ Python 编辑快反馈可执行 `codeguard lint python . --file src/changed.py -
180180

181181
**公开 `0.1.2` 尚未实现内置 WASM 兜底或自动对话交付。** 保留已有命令作为统一入口;当前仍须满足各原生适配器的参数和前置条件:
182182

183-
可选源码构建已有 Java/TypeScript 单文件候选路径。TypeScript 项目若有可见的本地 ESLint 10 入口和唯一 flat config,会先尝试从 `PATH` 解析 Node 并运行既有有界原生探针;缺 Node 时报告准备缺口;仅本地 ESLint 包未观察到时才提供 TypeScript/TSX 疑似语法初检。入口、包身份或配置不可信时保留具体环境阻塞。Java 候选仍须原生确认,所有内置 grammar 的版本/方言尚未验收,原生局部观察和初检都不能批准交付。默认及公开二进制沿用既有原生上下文路径,见 [Java 局部验收](tests/acceptance/java-syntax-fallback-candidate.md)、[TypeScript 局部验收](tests/acceptance/typescript-syntax-fallback-candidate.md)与[原生优先局部验收](tests/acceptance/native-first-eslint-candidate.md)。
183+
可选源码构建已有 Java/TypeScript 单文件候选路径。TypeScript 项目若有可见的本地 ESLint 10 入口和唯一 flat config,会先尝试从 `PATH` 解析 Node 并运行既有有界原生探针;缺 Node 时报告准备缺口;仅本地 ESLint 包未观察到时才提供 TypeScript/TSX 疑似语法初检。入口、包身份或配置不可信时保留具体环境阻塞。Java 候选仍须原生确认。Python `lint` 先保留 Ruff 结果,在 Ruff 缺失或项目未声明配置时补充疑似位置;损坏的 Ruff 配置仍是环境阻塞。所有内置 grammar 的版本/方言尚未验收,原生局部观察和初检都不能批准交付。默认及公开二进制沿用既有原生上下文路径,见 [Java 局部验收](tests/acceptance/java-syntax-fallback-candidate.md)、[TypeScript 局部验收](tests/acceptance/typescript-syntax-fallback-candidate.md)与[原生优先局部验收](tests/acceptance/native-first-eslint-candidate.md)。
184184

185185
已初始化工作区使用 `--workspace` 时,TypeScript/TSX 候选回退在同步后返回真实且稳定的原生确认任务 ID;反复 WASM 扫描不会自行关闭任务。版本化本地报告已按源码与 grammar 身份保存有界疑似位置;能力匹配的原生关闭仍待实现,见[局部验收](tests/acceptance/typescript-syntax-confirmation-task.md)。
186186

‎crates/codeguard-cli/src/eslint_preparation.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub(crate) fn prepare(
6666
"affected_paths":[relative],"source_sha256":format!("{:x}",Sha256::digest(bytes))}),
6767
)
6868
}
69-
#[cfg(unix)]
69+
#[cfg(all(unix, feature = "wasm-precheck"))]
7070
pub(crate) fn prepare_with_syntax(
7171
root: &Path,
7272
args: &EslintLintArguments,

‎crates/codeguard-cli/src/eslint_syntax_evidence.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! ESLint 原生确认任务中的脱敏 WASM 疑似位置;只具待核实证据权威。
22
33
use codeguard_adapters::bundled_grammar_candidates;
4-
use serde_json::{Value, json};
4+
use serde_json::Value;
5+
#[cfg(feature = "wasm-precheck")]
6+
use serde_json::json;
57
use sha2::{Digest, Sha256};
68

79
/// 从当轮候选反馈提取有界坐标,不保存源码片段或语法节点文本。
810
/// 参数为初检反馈、工作区相对路径和当前源码字节;返回绑定固定 grammar 的疑似证据。
11+
#[cfg(feature = "wasm-precheck")]
912
pub(crate) fn project(precheck: &Value, scope: &str, source: &[u8]) -> Result<Value, &'static str> {
1013
let observations = precheck["observations"]
1114
.as_array()

‎crates/codeguard-cli/src/eslint_workbench.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub(crate) fn connect_preparation(root: &Path, args: &EslintLintArguments, reaso
2828
Err(reason) => json!({"status":reason}),
2929
}
3030
}
31+
#[cfg(feature = "wasm-precheck")]
3132
pub(crate) fn connect_syntax_preparation(
3233
root: &Path,
3334
args: &EslintLintArguments,

‎crates/codeguard-cli/src/lib.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ pub(crate) mod python_cve_task_recheck;
148148
pub mod python_lint_command;
149149
#[cfg(unix)]
150150
pub mod python_lint_scan;
151+
#[cfg(all(unix, feature = "wasm-precheck"))]
152+
mod python_syntax_precheck;
151153
pub mod quality_policy_candidate;
152154
#[cfg(unix)]
153155
mod report_export;

‎crates/codeguard-cli/src/python_lint_command.rs‎

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ pub fn run(args: &[String]) -> ExitCode {
105105
feedback["scan_scope"] = Value::String("discovered_python".into());
106106
feedback["requested_paths"] = Value::Null;
107107
}
108-
let request_cancelled = codeguard_runtime::sigint_cancellation_requested()
108+
let cancellation_observed = codeguard_runtime::sigint_cancellation_requested()
109109
|| feedback["incomplete_reasons"]
110110
.as_array()
111111
.is_some_and(|reasons| reasons.iter().any(|reason| reason == "request_cancelled"));
112+
#[cfg(feature = "wasm-precheck")]
113+
let mut request_cancelled = cancellation_observed;
114+
#[cfg(not(feature = "wasm-precheck"))]
115+
let request_cancelled = cancellation_observed;
112116
if request_cancelled {
113117
feedback["command_status"] = Value::String("cancelled".into());
114118
feedback["exit_code"] = Value::from(130);
@@ -118,6 +122,51 @@ pub fn run(args: &[String]) -> ExitCode {
118122
}
119123
}
120124
}
125+
#[cfg(feature = "wasm-precheck")]
126+
if !request_cancelled {
127+
if let Some(precheck) = crate::python_syntax_precheck::observe(&root, &feedback, deadline) {
128+
feedback["schema_version"] = Value::String("0.14.0".into());
129+
feedback["scope"] = Value::String("local_native_and_candidate_syntax_scan".into());
130+
feedback["execution_budget"]["enforcement"] =
131+
Value::String("native_and_bounded_syntax_worker".into());
132+
let native_reasons: std::collections::BTreeSet<&str> = feedback["files"]
133+
.as_array()
134+
.into_iter()
135+
.flatten()
136+
.filter_map(|file| file["reason"].as_str())
137+
.collect();
138+
let native_reason = if native_reasons.len() == 1 {
139+
native_reasons
140+
.iter()
141+
.next()
142+
.copied()
143+
.unwrap_or("native_context_unavailable")
144+
} else {
145+
"multiple_native_incomplete_reasons"
146+
};
147+
feedback["native"] = serde_json::json!({"status":"incomplete","reason":native_reason});
148+
feedback["setup"] = serde_json::json!({"requirement":"required","reason":"native_confirmation_needed","task_id":null});
149+
feedback["next_action"] = Value::String(
150+
if precheck["observations"].as_array().is_some_and(|rows| !rows.is_empty()) {
151+
"核对 Python 疑似语法位置,确认项目要求的原生检查器及配置,再以适用的 Python 原生语法能力复检;勿凭候选初检修改源码或关闭任务"
152+
} else {
153+
"候选 Python grammar 版本尚未验收;确认项目要求的原生检查器及配置后复检,不把零恢复节点当作通过"
154+
}.into(),
155+
);
156+
feedback["syntax_precheck"] = precheck;
157+
}
158+
}
159+
#[cfg(feature = "wasm-precheck")]
160+
if !request_cancelled && codeguard_runtime::sigint_cancellation_requested() {
161+
request_cancelled = true;
162+
feedback["command_status"] = Value::String("cancelled".into());
163+
feedback["exit_code"] = Value::from(130);
164+
if let Some(reasons) = feedback["incomplete_reasons"].as_array_mut() {
165+
if !reasons.iter().any(|reason| reason == "request_cancelled") {
166+
reasons.push(Value::String("request_cancelled".into()));
167+
}
168+
}
169+
}
121170
if parsed.json {
122171
println!("{feedback}");
123172
} else {
@@ -632,7 +681,7 @@ fn create_scratch(run_id: &str) -> std::io::Result<PrivateScratch> {
632681
}
633682

634683
fn print_human(feedback: &Value) {
635-
println!("CodeGuard Python lint:局部原生检查;完整质量门禁尚未评估");
684+
println!("CodeGuard Python lint:局部检查;完整质量门禁尚未评估");
636685
println!(
637686
"本轮范围:{};目标:{}",
638687
feedback["scan_scope"].as_str().unwrap_or("unknown"),
@@ -732,6 +781,32 @@ fn print_human(feedback: &Value) {
732781
}
733782
}
734783
}
784+
if feedback["syntax_precheck"].is_object() {
785+
let precheck = &feedback["syntax_precheck"];
786+
println!(
787+
"内置 Python 语法候选初检:已检查 {} / {},疑似位置 {},状态 incomplete;候选涉及文件的原生 Ruff 未运行。",
788+
precheck["checked_files"],
789+
precheck["selected_files"],
790+
precheck["observations"].as_array().map_or(0, Vec::len)
791+
);
792+
for row in precheck["observations"]
793+
.as_array()
794+
.into_iter()
795+
.flatten()
796+
.take(8)
797+
{
798+
println!(
799+
"疑似语法 {}:{}:{} {};须由原生工具确认。",
800+
row["path"], row["start_line"], row["start_column"], row["kind"]
801+
);
802+
}
803+
println!(
804+
"下一步:{}",
805+
feedback["next_action"]
806+
.as_str()
807+
.unwrap_or("复查原生检查条件")
808+
);
809+
}
735810
println!("本命令尚无批准策略与完整义务,交付判定:not_evaluated");
736811
}
737812

0 commit comments

Comments
 (0)