Skip to main content

tokf_hook_types/
config.rs

1use serde::{Deserialize, Serialize};
2
3use crate::engine::ExternalEngineConfig;
4
5const fn default_true() -> bool {
6    true
7}
8
9/// User-provided overrides loaded from `rewrites.toml`.
10#[derive(Debug, Clone, Default, Deserialize, Serialize)]
11pub struct RewriteConfig {
12    /// Additional skip patterns (commands matching these are never rewritten).
13    pub skip: Option<SkipConfig>,
14
15    /// Pipe stripping and prefer-less-context behaviour.
16    pub pipe: Option<PipeConfig>,
17
18    /// User-defined rewrite rules (checked before auto-generated filter rules).
19    #[serde(default, skip_serializing_if = "Vec::is_empty")]
20    pub rewrite: Vec<RewriteRule>,
21
22    /// Permission engine configuration (external sub-hook delegation).
23    pub permissions: Option<PermissionsConfig>,
24
25    /// Debug/diagnostic settings (all off by default).
26    pub debug: Option<DebugConfig>,
27
28    /// Commands whose argv is opaque to tokf because it executes in a
29    /// different shell environment (typically a remote host or container).
30    /// User regex `[[rewrite]]` rules are not applied to these commands —
31    /// only argv-preserving wraps (`tokf run <cmd>`) and pipe-flag injection
32    /// remain.
33    pub transparent: Option<TransparentConfig>,
34}
35
36/// "Transparent-arg" commands: their last argument is opaque shell code.
37///
38/// Built-in list (always active): `ssh`, `mosh`, `slogin`. The `commands`
39/// field extends — does not replace — the built-in list. tokf must not
40/// splice text into the argv of these commands via regex rewrites.
41#[derive(Debug, Clone, Default, Deserialize, Serialize)]
42pub struct TransparentConfig {
43    /// Additional command basenames to treat as transparent. Matched against
44    /// the basename of the command's first word, so `kubectl` matches both
45    /// `kubectl` and `/usr/local/bin/kubectl`.
46    #[serde(default)]
47    pub commands: Vec<String>,
48}
49
50/// Debug and diagnostic settings for the rewrite system.
51#[derive(Debug, Clone, Default, Deserialize, Serialize)]
52pub struct DebugConfig {
53    /// When true, log to stderr when the bash parser (rable) fails to parse a
54    /// command. This helps diagnose "unmatched quote" errors by showing whether
55    /// tokf fell back to simple string matching because the AST parse failed.
56    #[serde(default)]
57    pub log_parse_failures: bool,
58}
59
60/// Configuration for the permission decision engine.
61#[derive(Debug, Clone, Deserialize, Serialize)]
62pub struct PermissionsConfig {
63    /// Which engine to use: `"builtin"` (default) or `"external"`.
64    #[serde(default)]
65    pub engine: PermissionEngineType,
66
67    /// Configuration for the external engine (required when `engine = "external"`).
68    pub external: Option<ExternalEngineConfig>,
69}
70
71/// Which permission engine to use.
72#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
73#[serde(rename_all = "lowercase")]
74pub enum PermissionEngineType {
75    /// Built-in deny/ask rule matching from Claude Code settings.json.
76    #[default]
77    Builtin,
78    /// Delegate to an external process (sub-hook).
79    External,
80}
81
82/// Controls how tokf handles piped commands during rewriting.
83#[derive(Debug, Clone, Deserialize, Serialize)]
84pub struct PipeConfig {
85    /// Whether to strip simple pipes (tail/head/grep) when a filter matches.
86    /// Default: true (current behaviour).
87    #[serde(default = "default_true")]
88    pub strip: bool,
89
90    /// When true and a pipe is stripped, inject `--prefer-less` so that at
91    /// runtime tokf compares filtered vs piped output and uses whichever is
92    /// smaller.
93    #[serde(default)]
94    pub prefer_less: bool,
95}
96
97/// Extra skip patterns from user config.
98#[derive(Debug, Clone, Default, Deserialize, Serialize)]
99pub struct SkipConfig {
100    /// Regex patterns — if any matches the command, rewriting is skipped.
101    #[serde(default)]
102    pub patterns: Vec<String>,
103}
104
105/// A single rewrite rule: match a command and replace it.
106#[derive(Debug, Clone, Deserialize, Serialize)]
107pub struct RewriteRule {
108    /// Regex pattern to match against the command string.
109    #[serde(rename = "match")]
110    pub match_pattern: String,
111
112    /// Replacement template. Supports `{0}` (full match), `{1}`, `{2}`, etc.
113    pub replace: String,
114}