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}