§9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
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.
This commit is contained in:
@@ -144,13 +144,13 @@ pub struct PromptContext {
|
||||
/// stdio / generic-ACP).
|
||||
#[serde(default)]
|
||||
pub is_non_interactive: bool,
|
||||
/// Identity in the primary grok-build system prompt (`You are <label>…`).
|
||||
/// Identity in the primary kigi system prompt (`You are <label>…`).
|
||||
/// Not the UI picker name. Defaults to [`DEFAULT_SYSTEM_PROMPT_LABEL`].
|
||||
#[serde(default = "default_system_prompt_label")]
|
||||
pub system_prompt_label: String,
|
||||
}
|
||||
/// Default identity on trim-tool-descriptions (`You are Grok released by xAI`).
|
||||
pub const DEFAULT_SYSTEM_PROMPT_LABEL: &str = "Grok";
|
||||
/// Default identity on trim-tool-descriptions (`You are Kigi released by xAI`).
|
||||
pub const DEFAULT_SYSTEM_PROMPT_LABEL: &str = "Kigi";
|
||||
fn default_system_prompt_label() -> String {
|
||||
DEFAULT_SYSTEM_PROMPT_LABEL.to_string()
|
||||
}
|
||||
@@ -427,9 +427,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_placeholders_system_prompt_label_override() {
|
||||
let mut ctx = test_context();
|
||||
ctx.system_prompt_label = "Grok Internal".into();
|
||||
ctx.system_prompt_label = "Kigi Internal".into();
|
||||
let p = ctx.placeholders();
|
||||
assert_eq!(p["system_prompt_label"], "Grok Internal");
|
||||
assert_eq!(p["system_prompt_label"], "Kigi Internal");
|
||||
}
|
||||
#[test]
|
||||
fn test_missing_system_prompt_label_deserializes_to_default() {
|
||||
@@ -1229,7 +1229,7 @@ mod tests {
|
||||
("plan", plan),
|
||||
] {
|
||||
assert!(
|
||||
!prompt.contains("You are a Grok Build agent"),
|
||||
!prompt.contains("You are a Kigi agent"),
|
||||
"{name} prompt should not duplicate base template identity"
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -832,12 +832,12 @@ mod tests {
|
||||
fn find_skill_paths_flat_layout() {
|
||||
// Traditional flat layout: skills/<name>/SKILL.md
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
|
||||
write_skill_md(&grok_dir.join("skills").join("alpha"), "alpha");
|
||||
write_skill_md(&grok_dir.join("skills").join("beta"), "beta");
|
||||
write_skill_md(&kigi_dir.join("skills").join("alpha"), "alpha");
|
||||
write_skill_md(&kigi_dir.join("skills").join("beta"), "beta");
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert_eq!(paths.len(), 2);
|
||||
assert!(paths.iter().all(|p| p.file_name().unwrap() == "SKILL.md"));
|
||||
}
|
||||
@@ -846,13 +846,13 @@ mod tests {
|
||||
fn find_skill_paths_nested_layout() {
|
||||
// Nested: skills/team/infra/SKILL.md, skills/team/training/SKILL.md
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
let skills = grok_dir.join("skills");
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
let skills = kigi_dir.join("skills");
|
||||
|
||||
write_skill_md(&skills.join("team").join("infra"), "infra");
|
||||
write_skill_md(&skills.join("team").join("training"), "training");
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert_eq!(paths.len(), 2);
|
||||
|
||||
let path_strs: Vec<String> = paths.iter().map(|p| p.display().to_string()).collect();
|
||||
@@ -864,8 +864,8 @@ mod tests {
|
||||
fn find_skill_paths_mixed_flat_and_nested() {
|
||||
// Mix of flat and nested skills
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
let skills = grok_dir.join("skills");
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
let skills = kigi_dir.join("skills");
|
||||
|
||||
// Flat
|
||||
write_skill_md(&skills.join("top-level"), "top-level");
|
||||
@@ -874,7 +874,7 @@ mod tests {
|
||||
// Nested 2 levels
|
||||
write_skill_md(&skills.join("org").join("team").join("deep"), "deep");
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert_eq!(paths.len(), 3);
|
||||
}
|
||||
|
||||
@@ -882,8 +882,8 @@ mod tests {
|
||||
fn find_skill_paths_dir_without_skill_md_is_skipped() {
|
||||
// A subdirectory exists but has no SKILL.md — should not appear
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
let skills = grok_dir.join("skills");
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
let skills = kigi_dir.join("skills");
|
||||
|
||||
write_skill_md(&skills.join("valid"), "valid");
|
||||
// Create a dir with no SKILL.md
|
||||
@@ -893,7 +893,7 @@ mod tests {
|
||||
fs::create_dir_all(&other).unwrap();
|
||||
fs::write(other.join("README.md"), "not a skill").unwrap();
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert_eq!(paths.len(), 1);
|
||||
assert!(paths[0].display().to_string().contains("valid"));
|
||||
}
|
||||
@@ -902,10 +902,10 @@ mod tests {
|
||||
fn find_skill_paths_no_skills_dir() {
|
||||
// .kigi exists but no skills/ subdirectory
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
fs::create_dir_all(&grok_dir).unwrap();
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
fs::create_dir_all(&kigi_dir).unwrap();
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert!(paths.is_empty());
|
||||
}
|
||||
|
||||
@@ -944,15 +944,15 @@ mod tests {
|
||||
fn find_skill_paths_parent_and_child_both_have_skill_md() {
|
||||
// A directory has SKILL.md and also has subdirectories with SKILL.md
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let grok_dir = tmp.path().join(".kigi");
|
||||
let skills = grok_dir.join("skills");
|
||||
let kigi_dir = tmp.path().join(".kigi");
|
||||
let skills = kigi_dir.join("skills");
|
||||
|
||||
// Parent skill
|
||||
write_skill_md(&skills.join("parent"), "parent-skill");
|
||||
// Child skill inside parent
|
||||
write_skill_md(&skills.join("parent").join("child"), "child-skill");
|
||||
|
||||
let paths = find_skill_paths(&grok_dir);
|
||||
let paths = find_skill_paths(&kigi_dir);
|
||||
assert_eq!(paths.len(), 2);
|
||||
|
||||
let path_strs: Vec<String> = paths.iter().map(|p| p.display().to_string()).collect();
|
||||
@@ -1108,9 +1108,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn parse_model_and_effort() {
|
||||
let content = "---\nname: my-skill\ndescription: test\nmodel: grok-3\neffort: high\n---\n";
|
||||
let content = "---\nname: my-skill\ndescription: test\nmodel: kigi-3\neffort: high\n---\n";
|
||||
let parsed = parse_skill_frontmatter(content, None).unwrap();
|
||||
assert_eq!(parsed.model.as_deref(), Some("grok-3"));
|
||||
assert_eq!(parsed.model.as_deref(), Some("kigi-3"));
|
||||
assert_eq!(parsed.effort.as_deref(), Some("high"));
|
||||
}
|
||||
|
||||
@@ -1251,7 +1251,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parse_full_spec_plus_extensions() {
|
||||
// Mixed agentskills.io spec fields + our extensions — all must parse.
|
||||
let content = "---\nname: my-skill\ndescription: A full skill\nlicense: MIT\ncompatibility: Python 3.12+\nmetadata:\n author: test-org\n version: \"2.0\"\nallowed-tools:\n - bash\n - read_file\nargument-hint: file path\nmodel: grok-3\neffort: high\nuser-invocable: true\ndisable-model-invocation: false\n---\nBody content.\n";
|
||||
let content = "---\nname: my-skill\ndescription: A full skill\nlicense: MIT\ncompatibility: Python 3.12+\nmetadata:\n author: test-org\n version: \"2.0\"\nallowed-tools:\n - bash\n - read_file\nargument-hint: file path\nmodel: kigi-3\neffort: high\nuser-invocable: true\ndisable-model-invocation: false\n---\nBody content.\n";
|
||||
let parsed = parse_skill_frontmatter(content, None).unwrap();
|
||||
assert_eq!(parsed.name, "my-skill");
|
||||
assert_eq!(parsed.description, "A full skill");
|
||||
@@ -1263,7 +1263,7 @@ mod tests {
|
||||
Some(["bash".to_string(), "read_file".to_string()].as_slice())
|
||||
);
|
||||
assert_eq!(parsed.argument_hint.as_deref(), Some("file path"));
|
||||
assert_eq!(parsed.model.as_deref(), Some("grok-3"));
|
||||
assert_eq!(parsed.model.as_deref(), Some("kigi-3"));
|
||||
assert_eq!(parsed.effort.as_deref(), Some("high"));
|
||||
assert!(parsed.user_invocable);
|
||||
assert!(!parsed.disable_model_invocation);
|
||||
@@ -1575,7 +1575,7 @@ mod tests {
|
||||
root: root.clone(),
|
||||
canonical_root: root.clone(),
|
||||
scope: PluginScope::User,
|
||||
origin: crate::plugins::PluginOrigin::UserGrok,
|
||||
origin: crate::plugins::PluginOrigin::UserKigi,
|
||||
trusted: true,
|
||||
enabled: true,
|
||||
version: Some("1.0.0".to_string()),
|
||||
@@ -1653,7 +1653,7 @@ mod tests {
|
||||
root: root.to_path_buf(),
|
||||
canonical_root: root.to_path_buf(),
|
||||
scope: PluginScope::User,
|
||||
origin: crate::plugins::PluginOrigin::UserGrok,
|
||||
origin: crate::plugins::PluginOrigin::UserKigi,
|
||||
trusted: true,
|
||||
skill_dirs,
|
||||
command_dirs: vec![],
|
||||
@@ -2323,7 +2323,7 @@ mod tests {
|
||||
root: root.clone(),
|
||||
canonical_root: root,
|
||||
scope: PluginScope::Project,
|
||||
origin: crate::plugins::PluginOrigin::ProjectGrok,
|
||||
origin: crate::plugins::PluginOrigin::ProjectKigi,
|
||||
trusted: true,
|
||||
enabled: true,
|
||||
version: Some("1.0.0".to_string()),
|
||||
@@ -2458,7 +2458,7 @@ mod tests {
|
||||
"cursor must be gated off: {dirs:?}"
|
||||
);
|
||||
assert!(ends_with(&dirs, ".claude"), "claude must remain: {dirs:?}");
|
||||
assert!(ends_with(&dirs, ".kigi"), "grok must remain: {dirs:?}");
|
||||
assert!(ends_with(&dirs, ".kigi"), "kigi must remain: {dirs:?}");
|
||||
}
|
||||
|
||||
// ── Same-scope frontmatter-name collisions (copied skill dirs) ──────
|
||||
|
||||
@@ -32,7 +32,7 @@ pub(crate) fn base_template() -> Zeroizing<String> {
|
||||
decrypt(BASE_PROMPT_ENC, PROMPT_SEEDS[0])
|
||||
}
|
||||
|
||||
/// The base prompt template source, exposed for `grok prompt --section template`.
|
||||
/// The base prompt template source, exposed for `kigi prompt --section template`.
|
||||
pub fn base_template_source() -> Zeroizing<String> {
|
||||
base_template()
|
||||
}
|
||||
@@ -41,7 +41,7 @@ pub(crate) fn apply_patch_template() -> Zeroizing<String> {
|
||||
decrypt(CODEX_PROMPT_ENC, PROMPT_SEEDS[1])
|
||||
}
|
||||
|
||||
/// Apply-patch prompt template source, exposed for `grok prompt --section apply-patch-template`.
|
||||
/// Apply-patch prompt template source, exposed for `kigi prompt --section apply-patch-template`.
|
||||
pub fn apply_patch_template_source() -> Zeroizing<String> {
|
||||
apply_patch_template()
|
||||
}
|
||||
@@ -93,7 +93,7 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Build a TemplateRenderer with the standard grok-build tool kinds.
|
||||
/// Build a TemplateRenderer with the standard kigi tool kinds.
|
||||
fn default_renderer() -> TemplateRenderer {
|
||||
let tools: HashMap<ToolKind, String> = [
|
||||
(ToolKind::Read, "read_file"),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! workspace overview, optional rules / skills / MCP listings).
|
||||
//!
|
||||
//! `UserMessageTemplate` selects the rendering strategy:
|
||||
//! - `Default` -- the legacy Grok Build prefix (built by the shell layer).
|
||||
//! - `Default` -- the legacy Kigi prefix (built by the shell layer).
|
||||
//! - `Custom` -- caller-supplied template string (MiniJinja, same delimiters
|
||||
//! as the system prompt templates).
|
||||
//!
|
||||
@@ -63,7 +63,7 @@ fn normalize_git_status(status: &str) -> Option<String> {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserMessageTemplate {
|
||||
/// Legacy Grok Build prefix: `<user_info>` + optional `<git_status>`.
|
||||
/// Legacy Kigi prefix: `<user_info>` + optional `<git_status>`.
|
||||
/// Built directly by the shell layer; this
|
||||
/// renderer returns `None` for `Default` and the caller falls back to
|
||||
/// its own legacy path.
|
||||
|
||||
Reference in New Issue
Block a user