diff --git a/scripts/dev-api.js b/scripts/dev-api.js
index 2e10ced..6e02ae0 100644
--- a/scripts/dev-api.js
+++ b/scripts/dev-api.js
@@ -3800,6 +3800,22 @@ export function buildHermesKanbanConfigValues(config = {}) {
1000,
false,
),
+ workerLogRotateBytes: parseHermesInteger(
+ kanban.worker_log_rotate_bytes,
+ 'kanban.worker_log_rotate_bytes',
+ 2097152,
+ 1,
+ 1073741824,
+ false,
+ ),
+ workerLogBackupCount: parseHermesInteger(
+ kanban.worker_log_backup_count,
+ 'kanban.worker_log_backup_count',
+ 1,
+ 0,
+ 100,
+ false,
+ ),
dispatchStaleTimeoutSeconds: parseHermesInteger(
kanban.dispatch_stale_timeout_seconds,
'kanban.dispatch_stale_timeout_seconds',
@@ -3864,6 +3880,22 @@ export function mergeHermesKanbanConfig(config = {}, form = {}) {
1000,
true,
)
+ kanban.worker_log_rotate_bytes = parseHermesInteger(
+ Object.hasOwn(form, 'workerLogRotateBytes') ? form.workerLogRotateBytes : currentValues.workerLogRotateBytes,
+ 'kanban.worker_log_rotate_bytes',
+ 2097152,
+ 1,
+ 1073741824,
+ true,
+ )
+ kanban.worker_log_backup_count = parseHermesInteger(
+ Object.hasOwn(form, 'workerLogBackupCount') ? form.workerLogBackupCount : currentValues.workerLogBackupCount,
+ 'kanban.worker_log_backup_count',
+ 1,
+ 0,
+ 100,
+ true,
+ )
kanban.dispatch_stale_timeout_seconds = parseHermesInteger(
Object.hasOwn(form, 'dispatchStaleTimeoutSeconds') ? form.dispatchStaleTimeoutSeconds : currentValues.dispatchStaleTimeoutSeconds,
'kanban.dispatch_stale_timeout_seconds',
diff --git a/src-tauri/src/commands/hermes.rs b/src-tauri/src/commands/hermes.rs
index e62b2e3..264f07c 100644
--- a/src-tauri/src/commands/hermes.rs
+++ b/src-tauri/src/commands/hermes.rs
@@ -6589,6 +6589,22 @@ fn build_hermes_kanban_config_values(config: &serde_yaml::Value) -> Value {
1000,
))
.unwrap_or(3),
+ "workerLogRotateBytes": kanban
+ .map(|map| bounded_hermes_i64(
+ yaml_i64_field(map, "worker_log_rotate_bytes"),
+ 2097152,
+ 1,
+ 1073741824,
+ ))
+ .unwrap_or(2097152),
+ "workerLogBackupCount": kanban
+ .map(|map| bounded_hermes_i64(
+ yaml_i64_field(map, "worker_log_backup_count"),
+ 1,
+ 0,
+ 100,
+ ))
+ .unwrap_or(1),
"dispatchStaleTimeoutSeconds": kanban
.map(|map| bounded_hermes_i64(
yaml_i64_field(map, "dispatch_stale_timeout_seconds"),
@@ -6644,6 +6660,20 @@ fn merge_hermes_kanban_config(config: &mut serde_yaml::Value, form: &Value) -> R
1,
1000,
)?;
+ let worker_log_rotate_bytes = validate_hermes_i64(
+ form_i64(form, "workerLogRotateBytes").or_else(|| current["workerLogRotateBytes"].as_i64()),
+ "kanban.worker_log_rotate_bytes",
+ 2097152,
+ 1,
+ 1073741824,
+ )?;
+ let worker_log_backup_count = validate_hermes_i64(
+ form_i64(form, "workerLogBackupCount").or_else(|| current["workerLogBackupCount"].as_i64()),
+ "kanban.worker_log_backup_count",
+ 1,
+ 0,
+ 100,
+ )?;
let stale_timeout = validate_hermes_i64(
form_i64(form, "dispatchStaleTimeoutSeconds")
.or_else(|| current["dispatchStaleTimeoutSeconds"].as_i64()),
@@ -6690,6 +6720,14 @@ fn merge_hermes_kanban_config(config: &mut serde_yaml::Value, form: &Value) -> R
yaml_key("auto_decompose_per_tick"),
serde_yaml::Value::Number(serde_yaml::Number::from(auto_decompose_per_tick)),
);
+ kanban.insert(
+ yaml_key("worker_log_rotate_bytes"),
+ serde_yaml::Value::Number(serde_yaml::Number::from(worker_log_rotate_bytes)),
+ );
+ kanban.insert(
+ yaml_key("worker_log_backup_count"),
+ serde_yaml::Value::Number(serde_yaml::Number::from(worker_log_backup_count)),
+ );
kanban.insert(
yaml_key("dispatch_stale_timeout_seconds"),
serde_yaml::Value::Number(serde_yaml::Number::from(stale_timeout)),
@@ -19460,6 +19498,8 @@ mod hermes_kanban_config_tests {
assert_eq!(values["failureLimit"], 2);
assert_eq!(values["autoDecompose"], true);
assert_eq!(values["autoDecomposePerTick"], 3);
+ assert_eq!(values["workerLogRotateBytes"], 2097152);
+ assert_eq!(values["workerLogBackupCount"], 1);
assert_eq!(values["dispatchStaleTimeoutSeconds"], 14400);
}
@@ -19475,6 +19515,8 @@ kanban:
failure_limit: "5"
auto_decompose: false
auto_decompose_per_tick: "7"
+ worker_log_rotate_bytes: "4194304"
+ worker_log_backup_count: "3"
dispatch_stale_timeout_seconds: "7200"
"#,
)
@@ -19487,6 +19529,8 @@ kanban:
assert_eq!(values["failureLimit"], 5);
assert_eq!(values["autoDecompose"], false);
assert_eq!(values["autoDecomposePerTick"], 7);
+ assert_eq!(values["workerLogRotateBytes"], 4194304);
+ assert_eq!(values["workerLogBackupCount"], 3);
assert_eq!(values["dispatchStaleTimeoutSeconds"], 7200);
}
@@ -19517,6 +19561,8 @@ memory:
"failureLimit": 4,
"autoDecompose": false,
"autoDecomposePerTick": 2,
+ "workerLogRotateBytes": 1048576,
+ "workerLogBackupCount": 0,
"dispatchStaleTimeoutSeconds": 0,
}),
)
@@ -19541,6 +19587,14 @@ memory:
config["kanban"]["auto_decompose_per_tick"].as_i64(),
Some(2)
);
+ assert_eq!(
+ config["kanban"]["worker_log_rotate_bytes"].as_i64(),
+ Some(1048576)
+ );
+ assert_eq!(
+ config["kanban"]["worker_log_backup_count"].as_i64(),
+ Some(0)
+ );
assert_eq!(
config["kanban"]["dispatch_stale_timeout_seconds"].as_i64(),
Some(0)
@@ -19595,6 +19649,14 @@ kanban:
.unwrap_err();
assert!(err.contains("kanban.auto_decompose_per_tick"));
+ let err = merge_hermes_kanban_config(&mut config, &json!({ "workerLogRotateBytes": 0 }))
+ .unwrap_err();
+ assert!(err.contains("kanban.worker_log_rotate_bytes"));
+
+ let err = merge_hermes_kanban_config(&mut config, &json!({ "workerLogBackupCount": -1 }))
+ .unwrap_err();
+ assert!(err.contains("kanban.worker_log_backup_count"));
+
let err =
merge_hermes_kanban_config(&mut config, &json!({ "dispatchStaleTimeoutSeconds": -1 }))
.unwrap_err();
diff --git a/src/engines/hermes/pages/config.js b/src/engines/hermes/pages/config.js
index b01ba1e..8b955e9 100644
--- a/src/engines/hermes/pages/config.js
+++ b/src/engines/hermes/pages/config.js
@@ -181,6 +181,8 @@ const KANBAN_DEFAULTS = {
failureLimit: 2,
autoDecompose: true,
autoDecomposePerTick: 3,
+ workerLogRotateBytes: 2097152,
+ workerLogBackupCount: 1,
dispatchStaleTimeoutSeconds: 14400,
}
@@ -1525,6 +1527,14 @@ export function render() {
${t('engine.hermesKanbanConfigAutoDecomposePerTick')}
+
+