The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok' crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party license archives, README provenance, and the required 'Based on Grok Build Open Source' attribution, now sourced from version_attribution.txt). Wire-visible renames (both sides in this repo, changed in lockstep): - Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode). - Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* / _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps a read-side alias for the legacy '_x.ai/session/update' method so existing updates.jsonl histories load; writes emit only the new name (both directions test-pinned). - Agent types grok-build* → kigi* with a documented legacy-prefix alias at resolution time so persisted sessions keep resolving. - ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build implementation dirs renamed to kigi*. - x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes grokday/groknight → kigiday/kiginight (old persisted values fall back to the default theme), web_fetch allowlist xAI hosts → kimi.com + moonshot platforms, changelog CDN → this repo, grok-build changelog archives deleted. - BYOK default endpoint removed: [endpoints] api_base_url is now truly optional with NO default — consumers fail fast with the flag name when unset (no silent x.ai egress). Mock harnesses inject it explicitly. - System-prompt identity fixed: 'released by xAI' → 'an unofficial community CLI for Kimi' (template + regenerated encrypted form). Also repaired pre-existing grok-era test debt found by the sweep: the stale trace_classify default-model pin, the grok-pager UA label test, pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY test could previously reach the real api.moonshot.cn), and the outdated oauth fixture scope key. Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings); FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed; deny advisories ok.
118 lines
4.1 KiB
Rust
118 lines
4.1 KiB
Rust
//! Shared hook source path discovery.
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use kigi_hooks::discovery::HookSource;
|
|
|
|
/// Owned paths for hook sources. Callers borrow via `as_sources()`.
|
|
pub struct HookSourcePaths {
|
|
pub global: Vec<PathBuf>,
|
|
pub project: Vec<PathBuf>,
|
|
}
|
|
|
|
impl HookSourcePaths {
|
|
/// Borrow as `HookSource` refs. Project sources are excluded when untrusted.
|
|
pub fn as_sources(&self, include_project: bool) -> (Vec<HookSource<'_>>, Vec<HookSource<'_>>) {
|
|
let global = self.global.iter().map(|p| path_to_source(p)).collect();
|
|
let project = if include_project {
|
|
self.project.iter().map(|p| path_to_source(p)).collect()
|
|
} else {
|
|
vec![]
|
|
};
|
|
(global, project)
|
|
}
|
|
}
|
|
|
|
fn path_to_source(p: &Path) -> HookSource<'_> {
|
|
if p.is_dir() {
|
|
HookSource::Directory(p)
|
|
} else {
|
|
HookSource::SettingsFile(p)
|
|
}
|
|
}
|
|
|
|
/// Build hook source paths for global (`~/`) and project (`<git_root>/`) scopes.
|
|
/// Callers gate project sources on trust via `as_sources(trusted)`.
|
|
pub fn discover_hook_source_paths(
|
|
git_root: Option<&Path>,
|
|
compat: &kigi_tools::types::compat::CompatConfig,
|
|
) -> HookSourcePaths {
|
|
// Compat gate: skip .claude hook sources when disabled.
|
|
let skip_claude_compat = !compat.claude.hooks;
|
|
// Phase 2 cutoff: if the user has imported, skip .claude/settings.json
|
|
// sources. Native .kigi/hooks/ directories are still scanned (they hold
|
|
// any hooks that were imported by /import-claude).
|
|
let skip_claude = skip_claude_compat
|
|
|| crate::claude_import::is_claude_import_marked_with_log("discover_hook_source_paths");
|
|
|
|
// Compat gate: skip Cursor hook sources when disabled.
|
|
let skip_cursor = !compat.cursor.hooks;
|
|
|
|
let home = dirs::home_dir();
|
|
// user_kigi_home() is None when no home resolves, so inspect lists the same
|
|
// sources a live session loads, instead of a cwd-relative .kigi.
|
|
let kigi = kigi_config::user_kigi_home();
|
|
let mut global = Vec::new();
|
|
|
|
if !skip_claude && let Some(ref h) = home {
|
|
global.push(h.join(".claude").join("settings.json"));
|
|
global.push(h.join(".claude").join("settings.local.json"));
|
|
}
|
|
if let Some(ref kigi) = kigi {
|
|
global.push(kigi.join("hooks"));
|
|
}
|
|
|
|
let custom_paths: Vec<PathBuf> = kigi
|
|
.as_ref()
|
|
.and_then(|g| std::fs::read_to_string(g.join("hooks-paths")).ok())
|
|
.map(|content| {
|
|
content
|
|
.lines()
|
|
.filter(|l| !l.trim().is_empty())
|
|
.map(|l| PathBuf::from(l.trim()))
|
|
.collect()
|
|
})
|
|
.unwrap_or_default();
|
|
global.extend(custom_paths);
|
|
|
|
if let Some(ref h) = home
|
|
&& !skip_cursor
|
|
{
|
|
global.push(h.join(".cursor").join("hooks.json"));
|
|
}
|
|
|
|
let mut project = Vec::new();
|
|
|
|
if let Some(root) = git_root {
|
|
if !skip_claude {
|
|
project.push(root.join(".claude").join("settings.json"));
|
|
project.push(root.join(".claude").join("settings.local.json"));
|
|
}
|
|
project.push(root.join(".kigi").join("hooks"));
|
|
if !skip_cursor {
|
|
project.push(root.join(".cursor").join("hooks.json"));
|
|
}
|
|
}
|
|
|
|
HookSourcePaths { global, project }
|
|
}
|
|
|
|
/// Single load entry point: build compat-aware sources, gate project sources on
|
|
/// trust, then load. Every session-startup and mid-session reload site routes
|
|
/// through here so the source policy stays in one place. `discover_hook_source_paths`
|
|
/// and `HookSourcePaths::as_sources` stay public for the `inspect` path (which
|
|
/// enumerates sources with all vendors on) and the unit tests that assert on the
|
|
/// raw source lists.
|
|
pub fn discover_hooks(
|
|
git_root: Option<&Path>,
|
|
compat: &kigi_tools::types::compat::CompatConfig,
|
|
trusted: bool,
|
|
) -> (
|
|
kigi_hooks::discovery::HookRegistry,
|
|
Vec<kigi_hooks::error::HookError>,
|
|
) {
|
|
let source_paths = discover_hook_source_paths(git_root, compat);
|
|
let (global_sources, project_sources) = source_paths.as_sources(trusted);
|
|
kigi_hooks::discovery::load_hooks_from_sources(&global_sources, &project_sources)
|
|
}
|