story-kit: done 199_story_web_ui_submits_all_queued_items_at_once
This commit is contained in:
@@ -9,6 +9,41 @@ pub struct ProjectConfig {
|
||||
pub component: Vec<ComponentConfig>,
|
||||
#[serde(default)]
|
||||
pub agent: Vec<AgentConfig>,
|
||||
#[serde(default)]
|
||||
pub watcher: WatcherConfig,
|
||||
}
|
||||
|
||||
/// Configuration for the filesystem watcher's sweep behaviour.
|
||||
///
|
||||
/// Controls how often the watcher checks `5_done/` for items to promote to
|
||||
/// `6_archived/`, and how long items must remain in `5_done/` before promotion.
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct WatcherConfig {
|
||||
/// How often (in seconds) to check `5_done/` for items to archive.
|
||||
/// Default: 60 seconds.
|
||||
#[serde(default = "default_sweep_interval_secs")]
|
||||
pub sweep_interval_secs: u64,
|
||||
/// How long (in seconds) an item must remain in `5_done/` before being
|
||||
/// moved to `6_archived/`. Default: 14400 (4 hours).
|
||||
#[serde(default = "default_done_retention_secs")]
|
||||
pub done_retention_secs: u64,
|
||||
}
|
||||
|
||||
impl Default for WatcherConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sweep_interval_secs: default_sweep_interval_secs(),
|
||||
done_retention_secs: default_done_retention_secs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_sweep_interval_secs() -> u64 {
|
||||
60
|
||||
}
|
||||
|
||||
fn default_done_retention_secs() -> u64 {
|
||||
4 * 60 * 60 // 4 hours
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -87,6 +122,8 @@ struct LegacyProjectConfig {
|
||||
#[serde(default)]
|
||||
component: Vec<ComponentConfig>,
|
||||
agent: Option<AgentConfig>,
|
||||
#[serde(default)]
|
||||
watcher: WatcherConfig,
|
||||
}
|
||||
|
||||
impl Default for ProjectConfig {
|
||||
@@ -107,6 +144,7 @@ impl Default for ProjectConfig {
|
||||
stage: None,
|
||||
inactivity_timeout_secs: default_inactivity_timeout_secs(),
|
||||
}],
|
||||
watcher: WatcherConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +185,7 @@ impl ProjectConfig {
|
||||
let config = ProjectConfig {
|
||||
component: legacy.component,
|
||||
agent: vec![agent],
|
||||
watcher: legacy.watcher,
|
||||
};
|
||||
validate_agents(&config.agent)?;
|
||||
return Ok(config);
|
||||
@@ -166,6 +205,7 @@ impl ProjectConfig {
|
||||
let config = ProjectConfig {
|
||||
component: legacy.component,
|
||||
agent: vec![agent],
|
||||
watcher: legacy.watcher,
|
||||
};
|
||||
validate_agents(&config.agent)?;
|
||||
Ok(config)
|
||||
@@ -173,6 +213,7 @@ impl ProjectConfig {
|
||||
Ok(ProjectConfig {
|
||||
component: legacy.component,
|
||||
agent: Vec::new(),
|
||||
watcher: legacy.watcher,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -517,4 +558,93 @@ model = "sonnet"
|
||||
assert_eq!(config.agent[0].name, "main");
|
||||
assert_eq!(config.agent[0].model, Some("sonnet".to_string()));
|
||||
}
|
||||
|
||||
// ── WatcherConfig ──────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn watcher_config_defaults_when_omitted() {
|
||||
let toml_str = r#"
|
||||
[[agent]]
|
||||
name = "coder"
|
||||
"#;
|
||||
let config = ProjectConfig::parse(toml_str).unwrap();
|
||||
assert_eq!(config.watcher.sweep_interval_secs, 60);
|
||||
assert_eq!(config.watcher.done_retention_secs, 4 * 60 * 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watcher_config_custom_values() {
|
||||
let toml_str = r#"
|
||||
[watcher]
|
||||
sweep_interval_secs = 30
|
||||
done_retention_secs = 7200
|
||||
|
||||
[[agent]]
|
||||
name = "coder"
|
||||
"#;
|
||||
let config = ProjectConfig::parse(toml_str).unwrap();
|
||||
assert_eq!(config.watcher.sweep_interval_secs, 30);
|
||||
assert_eq!(config.watcher.done_retention_secs, 7200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watcher_config_partial_override() {
|
||||
let toml_str = r#"
|
||||
[watcher]
|
||||
sweep_interval_secs = 10
|
||||
|
||||
[[agent]]
|
||||
name = "coder"
|
||||
"#;
|
||||
let config = ProjectConfig::parse(toml_str).unwrap();
|
||||
assert_eq!(config.watcher.sweep_interval_secs, 10);
|
||||
// done_retention_secs should fall back to the default (4 hours).
|
||||
assert_eq!(config.watcher.done_retention_secs, 4 * 60 * 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watcher_config_from_file() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".story_kit");
|
||||
fs::create_dir_all(&sk).unwrap();
|
||||
fs::write(
|
||||
sk.join("project.toml"),
|
||||
r#"
|
||||
[watcher]
|
||||
sweep_interval_secs = 120
|
||||
done_retention_secs = 3600
|
||||
|
||||
[[agent]]
|
||||
name = "coder"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.watcher.sweep_interval_secs, 120);
|
||||
assert_eq!(config.watcher.done_retention_secs, 3600);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watcher_config_default_when_no_file() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let config = ProjectConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.watcher, WatcherConfig::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watcher_config_preserved_in_legacy_format() {
|
||||
let toml_str = r#"
|
||||
[watcher]
|
||||
sweep_interval_secs = 15
|
||||
done_retention_secs = 900
|
||||
|
||||
[agent]
|
||||
command = "claude"
|
||||
"#;
|
||||
let config = ProjectConfig::parse(toml_str).unwrap();
|
||||
assert_eq!(config.watcher.sweep_interval_secs, 15);
|
||||
assert_eq!(config.watcher.done_retention_secs, 900);
|
||||
assert_eq!(config.agent.len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user