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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli

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.

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.
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.

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.
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.

### npm installation and one-off use

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

**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:

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).
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).

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).

Expand Down
6 changes: 3 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli

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

工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java、TypeScript、TSX grammar 候选资产与有界 Rust worker,为缺少显式原生上下文的 `lint java`、`lint typescript` 单文件请求提供疑似语法观察;`.tsx` 使用独立 grammar。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。
工作区要求 `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 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。

当前源码构建的 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 限额。
当前源码构建的 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 限额。

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

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

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

可选源码构建已有 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)。
可选源码构建已有 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)。

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

Expand Down
2 changes: 1 addition & 1 deletion crates/codeguard-cli/src/eslint_preparation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub(crate) fn prepare(
"affected_paths":[relative],"source_sha256":format!("{:x}",Sha256::digest(bytes))}),
)
}
#[cfg(unix)]
#[cfg(all(unix, feature = "wasm-precheck"))]
pub(crate) fn prepare_with_syntax(
root: &Path,
args: &EslintLintArguments,
Expand Down
5 changes: 4 additions & 1 deletion crates/codeguard-cli/src/eslint_syntax_evidence.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//! ESLint 原生确认任务中的脱敏 WASM 疑似位置;只具待核实证据权威。

use codeguard_adapters::bundled_grammar_candidates;
use serde_json::{Value, json};
use serde_json::Value;
#[cfg(feature = "wasm-precheck")]
use serde_json::json;
use sha2::{Digest, Sha256};

/// 从当轮候选反馈提取有界坐标,不保存源码片段或语法节点文本。
/// 参数为初检反馈、工作区相对路径和当前源码字节;返回绑定固定 grammar 的疑似证据。
#[cfg(feature = "wasm-precheck")]
pub(crate) fn project(precheck: &Value, scope: &str, source: &[u8]) -> Result<Value, &'static str> {
let observations = precheck["observations"]
.as_array()
Expand Down
1 change: 1 addition & 0 deletions crates/codeguard-cli/src/eslint_workbench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) fn connect_preparation(root: &Path, args: &EslintLintArguments, reaso
Err(reason) => json!({"status":reason}),
}
}
#[cfg(feature = "wasm-precheck")]
pub(crate) fn connect_syntax_preparation(
root: &Path,
args: &EslintLintArguments,
Expand Down
2 changes: 2 additions & 0 deletions crates/codeguard-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pub(crate) mod python_cve_task_recheck;
pub mod python_lint_command;
#[cfg(unix)]
pub mod python_lint_scan;
#[cfg(all(unix, feature = "wasm-precheck"))]
mod python_syntax_precheck;
pub mod quality_policy_candidate;
#[cfg(unix)]
mod report_export;
Expand Down
79 changes: 77 additions & 2 deletions crates/codeguard-cli/src/python_lint_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,14 @@ pub fn run(args: &[String]) -> ExitCode {
feedback["scan_scope"] = Value::String("discovered_python".into());
feedback["requested_paths"] = Value::Null;
}
let request_cancelled = codeguard_runtime::sigint_cancellation_requested()
let cancellation_observed = codeguard_runtime::sigint_cancellation_requested()
|| feedback["incomplete_reasons"]
.as_array()
.is_some_and(|reasons| reasons.iter().any(|reason| reason == "request_cancelled"));
#[cfg(feature = "wasm-precheck")]
let mut request_cancelled = cancellation_observed;
#[cfg(not(feature = "wasm-precheck"))]
let request_cancelled = cancellation_observed;
if request_cancelled {
feedback["command_status"] = Value::String("cancelled".into());
feedback["exit_code"] = Value::from(130);
Expand All @@ -118,6 +122,51 @@ pub fn run(args: &[String]) -> ExitCode {
}
}
}
#[cfg(feature = "wasm-precheck")]
if !request_cancelled {
if let Some(precheck) = crate::python_syntax_precheck::observe(&root, &feedback, deadline) {
feedback["schema_version"] = Value::String("0.14.0".into());
feedback["scope"] = Value::String("local_native_and_candidate_syntax_scan".into());
feedback["execution_budget"]["enforcement"] =
Value::String("native_and_bounded_syntax_worker".into());
let native_reasons: std::collections::BTreeSet<&str> = feedback["files"]
.as_array()
.into_iter()
.flatten()
.filter_map(|file| file["reason"].as_str())
.collect();
let native_reason = if native_reasons.len() == 1 {
native_reasons
.iter()
.next()
.copied()
.unwrap_or("native_context_unavailable")
} else {
"multiple_native_incomplete_reasons"
};
feedback["native"] = serde_json::json!({"status":"incomplete","reason":native_reason});
feedback["setup"] = serde_json::json!({"requirement":"required","reason":"native_confirmation_needed","task_id":null});
feedback["next_action"] = Value::String(
if precheck["observations"].as_array().is_some_and(|rows| !rows.is_empty()) {
"核对 Python 疑似语法位置,确认项目要求的原生检查器及配置,再以适用的 Python 原生语法能力复检;勿凭候选初检修改源码或关闭任务"
} else {
"候选 Python grammar 版本尚未验收;确认项目要求的原生检查器及配置后复检,不把零恢复节点当作通过"
}.into(),
);
feedback["syntax_precheck"] = precheck;
}
}
#[cfg(feature = "wasm-precheck")]
if !request_cancelled && codeguard_runtime::sigint_cancellation_requested() {
request_cancelled = true;
feedback["command_status"] = Value::String("cancelled".into());
feedback["exit_code"] = Value::from(130);
if let Some(reasons) = feedback["incomplete_reasons"].as_array_mut() {
if !reasons.iter().any(|reason| reason == "request_cancelled") {
reasons.push(Value::String("request_cancelled".into()));
}
}
}
if parsed.json {
println!("{feedback}");
} else {
Expand Down Expand Up @@ -632,7 +681,7 @@ fn create_scratch(run_id: &str) -> std::io::Result<PrivateScratch> {
}

fn print_human(feedback: &Value) {
println!("CodeGuard Python lint:局部原生检查;完整质量门禁尚未评估");
println!("CodeGuard Python lint:局部检查;完整质量门禁尚未评估");
println!(
"本轮范围:{};目标:{}",
feedback["scan_scope"].as_str().unwrap_or("unknown"),
Expand Down Expand Up @@ -732,6 +781,32 @@ fn print_human(feedback: &Value) {
}
}
}
if feedback["syntax_precheck"].is_object() {
let precheck = &feedback["syntax_precheck"];
println!(
"内置 Python 语法候选初检:已检查 {} / {},疑似位置 {},状态 incomplete;候选涉及文件的原生 Ruff 未运行。",
precheck["checked_files"],
precheck["selected_files"],
precheck["observations"].as_array().map_or(0, Vec::len)
Comment on lines +786 to +790

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Surface unavailable syntax files in human output

When a candidate cannot be checked—for example because it exceeds 1 MiB, changes during the scan, or the worker times out—the default human renderer prints only aggregate counts and suspected observations. It never renders syntax_precheck.unavailable, so users cannot identify the skipped file or its reason even though the JSON report contains both; include the bounded unavailable paths and reasons in this section.

Useful? React with 👍 / 👎.

);
for row in precheck["observations"]
.as_array()
.into_iter()
.flatten()
.take(8)
{
println!(
"疑似语法 {}:{}:{} {};须由原生工具确认。",
row["path"], row["start_line"], row["start_column"], row["kind"]
);
}
println!(
"下一步:{}",
feedback["next_action"]
.as_str()
.unwrap_or("复查原生检查条件")
);
}
println!("本命令尚无批准策略与完整义务,交付判定:not_evaluated");
}

Expand Down
Loading
Loading