From 1fc418974656cd8581e4e89e04a7cf808495140c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 10:58:07 +0000 Subject: [PATCH] feat(coding-agent): generate the resolve-config-value query surface via fluessig Swap four hand-written `#[napi]` exports from coding-agent core/resolve-config-value.ts to the fluessig-generated path: author the ops in schema/api.json, add the matching `core_impl` delegations, regenerate src/generated.rs, and delete the hand-written exports from src/lib.rs. The four ops are proven primitive shapes: `getConfigValueEnvVarName(config) -> string | null` (nullable string), `getConfigValueEnvVarNames(config) -> Array` (list), `isCommandConfigValue(config) -> boolean` (bool), and `clearConfigValueCache() -> void` (void, no params). Each `core_impl` method reaches the SAME `pidgin_coding::core::resolve_config_value` function the hand-written export called, so JS-visible behavior is byte-for-byte unchanged. The module's other exports (resolveConfigValue*, resolveHeaders*, the env-JSON helpers) stay hand-written for now. Verified: each swapped symbol's generated `.d.ts` JSDoc+signature block, its `.js` `module.exports` line, and its nativeBinding destructure entry are byte-identical to a pre-swap build of the base (only file position moves into the generated cluster). cargo build/fmt/clippy clean; codespell 0; straitjacket 0 errors; the resolve-config-value oracle slice (coding-agent/test/resolve-config-value.test.ts, 10 tests) passes 10/10 against the locally-built generated addon. --- crates/pidgin-napi/schema/api.json | 75 +++++++++++++++++++++++++++++ crates/pidgin-napi/src/core_impl.rs | 16 ++++++ crates/pidgin-napi/src/generated.rs | 32 ++++++++++++ crates/pidgin-napi/src/lib.rs | 28 ----------- 4 files changed, 123 insertions(+), 28 deletions(-) diff --git a/crates/pidgin-napi/schema/api.json b/crates/pidgin-napi/schema/api.json index 8e8a5745..73716aa7 100644 --- a/crates/pidgin-napi/schema/api.json +++ b/crates/pidgin-napi/schema/api.json @@ -680,6 +680,81 @@ "name": "substituteArgs" } } + }, + { + "name": "getConfigValueEnvVarName", + "doc": "`getConfigValueEnvVarName` (resolve-config-value.ts): the single env var a\nvalue references, or `null` (pi's `undefined`).", + "shape": "unary", + "infallible": true, + "readonly": true, + "params": [ + { + "name": "config", + "type": "string" + } + ], + "returns": { + "nullable": "string" + }, + "bindings": { + "node": { + "name": "getConfigValueEnvVarName" + } + } + }, + { + "name": "getConfigValueEnvVarNames", + "doc": "`getConfigValueEnvVarNames` (resolve-config-value.ts): all distinct env var\nnames a value references, in first-seen order.", + "shape": "unary", + "infallible": true, + "readonly": true, + "params": [ + { + "name": "config", + "type": "string" + } + ], + "returns": { + "list": "string" + }, + "bindings": { + "node": { + "name": "getConfigValueEnvVarNames" + } + } + }, + { + "name": "isCommandConfigValue", + "doc": "`isCommandConfigValue` (resolve-config-value.ts): whether a value is a\n`!`-prefixed shell command.", + "shape": "unary", + "infallible": true, + "readonly": true, + "params": [ + { + "name": "config", + "type": "string" + } + ], + "returns": "boolean", + "bindings": { + "node": { + "name": "isCommandConfigValue" + } + } + }, + { + "name": "clearConfigValueCache", + "doc": "`clearConfigValueCache` (resolve-config-value.ts): clear the process-lifetime\n`!command` result cache.", + "shape": "unary", + "infallible": true, + "readonly": false, + "params": [], + "returns": "void", + "bindings": { + "node": { + "name": "clearConfigValueCache" + } + } } ] }, diff --git a/crates/pidgin-napi/src/core_impl.rs b/crates/pidgin-napi/src/core_impl.rs index 1c12e3a0..9563fe87 100644 --- a/crates/pidgin-napi/src/core_impl.rs +++ b/crates/pidgin-napi/src/core_impl.rs @@ -196,6 +196,22 @@ impl crate::generated::PidginCore for PidginImpl { let refs: Vec<&str> = args.iter().map(String::as_str).collect(); pidgin_agent::harness::prompt_templates::substitute_args(&content, &refs) } + + fn get_config_value_env_var_name(config: String) -> Option { + pidgin_coding::core::resolve_config_value::get_config_value_env_var_name(&config) + } + + fn get_config_value_env_var_names(config: String) -> Vec { + pidgin_coding::core::resolve_config_value::get_config_value_env_var_names(&config) + } + + fn is_command_config_value(config: String) -> bool { + pidgin_coding::core::resolve_config_value::is_command_config_value(&config) + } + + fn clear_config_value_cache() { + pidgin_coding::core::resolve_config_value::clear_config_value_cache(); + } } // --- coding-agent session-cwd seam (core/session-cwd.ts) -------------------- diff --git a/crates/pidgin-napi/src/generated.rs b/crates/pidgin-napi/src/generated.rs index 9bb9444c..61ac9204 100644 --- a/crates/pidgin-napi/src/generated.rs +++ b/crates/pidgin-napi/src/generated.rs @@ -91,6 +91,10 @@ pub trait PidginCore: Sized + Send + Sync + 'static { fn format_missing_session_cwd_prompt(issue: SessionCwdIssueJs) -> String; fn parse_command_args(args_string: String) -> Vec; fn substitute_args(content: String, args: Vec) -> String; + fn get_config_value_env_var_name(config: String) -> Option; + fn get_config_value_env_var_names(config: String) -> Vec; + fn is_command_config_value(config: String) -> bool; + fn clear_config_value_cache() -> (); } /// The `KeybindingsManagerCore` contract — implement over the engine in `crate::core_impl`. @@ -338,6 +342,34 @@ pub fn substitute_args(content: String, args: Vec) -> String { ::substitute_args(content, args) } +/// `getConfigValueEnvVarName` (resolve-config-value.ts): the single env var a +/// value references, or `null` (pi's `undefined`). +#[napi(js_name = "getConfigValueEnvVarName")] +pub fn get_config_value_env_var_name(config: String) -> Option { + ::get_config_value_env_var_name(config) +} + +/// `getConfigValueEnvVarNames` (resolve-config-value.ts): all distinct env var +/// names a value references, in first-seen order. +#[napi(js_name = "getConfigValueEnvVarNames")] +pub fn get_config_value_env_var_names(config: String) -> Vec { + ::get_config_value_env_var_names(config) +} + +/// `isCommandConfigValue` (resolve-config-value.ts): whether a value is a +/// `!`-prefixed shell command. +#[napi(js_name = "isCommandConfigValue")] +pub fn is_command_config_value(config: String) -> bool { + ::is_command_config_value(config) +} + +/// `clearConfigValueCache` (resolve-config-value.ts): clear the process-lifetime +/// `!command` result cache. +#[napi(js_name = "clearConfigValueCache")] +pub fn clear_config_value_cache() -> () { + ::clear_config_value_cache() +} + /// The Rust-backed keybindings core, exposed to JavaScript as /// `KeybindingsManagerCore`. #[napi] diff --git a/crates/pidgin-napi/src/lib.rs b/crates/pidgin-napi/src/lib.rs index 0a29c63e..e312a3ee 100644 --- a/crates/pidgin-napi/src/lib.rs +++ b/crates/pidgin-napi/src/lib.rs @@ -638,20 +638,6 @@ pub fn resolve_config_value_or_throw( .map_err(|e| napi::Error::from_reason(e.to_string())) } -/// `getConfigValueEnvVarName` (resolve-config-value.ts): the single env var a -/// value references, or `null` (pi's `undefined`). -#[napi(js_name = "getConfigValueEnvVarName")] -pub fn get_config_value_env_var_name(config: String) -> Option { - pidgin_coding::core::resolve_config_value::get_config_value_env_var_name(&config) -} - -/// `getConfigValueEnvVarNames` (resolve-config-value.ts): all distinct env var -/// names a value references, in first-seen order. -#[napi(js_name = "getConfigValueEnvVarNames")] -pub fn get_config_value_env_var_names(config: String) -> Vec { - pidgin_coding::core::resolve_config_value::get_config_value_env_var_names(&config) -} - /// `getMissingConfigValueEnvVarNames` (resolve-config-value.ts): referenced env /// var names that do not currently resolve. #[napi(js_name = "getMissingConfigValueEnvVarNames")] @@ -668,13 +654,6 @@ pub fn get_missing_config_value_env_var_names( ) } -/// `isCommandConfigValue` (resolve-config-value.ts): whether a value is a -/// `!`-prefixed shell command. -#[napi(js_name = "isCommandConfigValue")] -pub fn is_command_config_value(config: String) -> bool { - pidgin_coding::core::resolve_config_value::is_command_config_value(&config) -} - /// `isConfigValueConfigured` (resolve-config-value.ts): whether every env var a /// value references is set. #[napi(js_name = "isConfigValueConfigured")] @@ -733,13 +712,6 @@ pub fn resolve_headers_or_throw( headers_json(resolved) } -/// `clearConfigValueCache` (resolve-config-value.ts): clear the process-lifetime -/// `!command` result cache. -#[napi(js_name = "clearConfigValueCache")] -pub fn clear_config_value_cache() { - pidgin_coding::core::resolve_config_value::clear_config_value_cache(); -} - // --- coding-agent core: trust-manager --------------------------------------- // // Thin wrappers over `pidgin_coding::core::trust_manager`, backing the native