Refactor owner scope across channels and fix default routing fallback (#1151)

* refactor: add explicit owner scope across channels

* fix: tighten routine owner target routing

* fix: address owner scope review feedback

* Fix owner-scope onboarding and event trigger isolation

* Tighten routing fallback and wizard owner validation

* fix: address owner-scope follow-up review

* fix: tighten owner-scope follow-up details

* fix: import Channel trait in telegram test

* fix: normalize http webhook sender ids

* fix: address remaining owner-scope review issues

* fix: reconcile config rebase fallout

* fix: reconcile extension manager rebase drift

* fix: address current copilot review regressions

* fix: restore clippy matrix after rebase
This commit is contained in:
Henry Park
2026-03-16 13:31:03 -07:00
committed by GitHub
parent 971b4c2ef4
commit 878a67cdb6
50 changed files with 2767 additions and 1071 deletions
+19 -15
View File
@@ -153,7 +153,8 @@ async fn async_main() -> anyhow::Result<()> {
provider_only: *provider_only,
quick: *quick,
};
let mut wizard = SetupWizard::with_config(config);
let mut wizard =
SetupWizard::try_with_config_and_toml(config, cli.config.as_deref())?;
wizard.run().await?;
}
#[cfg(not(any(feature = "postgres", feature = "libsql")))]
@@ -195,10 +196,13 @@ async fn async_main() -> anyhow::Result<()> {
{
println!("Onboarding needed: {}", reason);
println!();
let mut wizard = SetupWizard::with_config(SetupConfig {
quick: true,
..Default::default()
});
let mut wizard = SetupWizard::try_with_config_and_toml(
SetupConfig {
quick: true,
..Default::default()
},
cli.config.as_deref(),
)?;
wizard.run().await?;
}
@@ -282,9 +286,12 @@ async fn async_main() -> anyhow::Result<()> {
// Create CLI channel
let repl_channel = if let Some(ref msg) = cli.message {
Some(ReplChannel::with_message(msg.clone()))
Some(ReplChannel::with_message_for_user(
config.owner_id.clone(),
msg.clone(),
))
} else if config.channels.cli.enabled {
let repl = ReplChannel::new();
let repl = ReplChannel::with_user_id(config.owner_id.clone());
repl.suppress_banner();
Some(repl)
} else {
@@ -311,12 +318,7 @@ async fn async_main() -> anyhow::Result<()> {
webhook_routes.push(webhooks::routes(ToolWebhookState {
tools: Arc::clone(&components.tools),
routine_engine: Arc::clone(&shared_routine_engine_slot),
user_id: config
.channels
.gateway
.as_ref()
.map(|g| g.user_id.clone())
.unwrap_or_else(|| "default".to_string()),
user_id: config.owner_id.clone(),
secrets_store: components.secrets_store.clone(),
}));
@@ -703,6 +705,7 @@ async fn async_main() -> anyhow::Result<()> {
.map(|db| Arc::clone(db) as Arc<dyn ironclaw::db::SettingsStore>);
let deps = AgentDeps {
owner_id: config.owner_id.clone(),
store: components.db,
llm: components.llm,
cheap_llm: components.cheap_llm,
@@ -775,6 +778,7 @@ async fn async_main() -> anyhow::Result<()> {
let sighup_webhook_server = webhook_server.clone();
let sighup_settings_store_clone = sighup_settings_store.clone();
let sighup_secrets_store = components.secrets_store.clone();
let sighup_owner_id = config.owner_id.clone();
let mut shutdown_rx = shutdown_tx.subscribe();
tokio::spawn(async move {
@@ -805,7 +809,7 @@ async fn async_main() -> anyhow::Result<()> {
if let Some(ref secrets_store) = sighup_secrets_store {
// Inject HTTP webhook secret from encrypted store
if let Ok(webhook_secret) = secrets_store
.get_decrypted("default", "http_webhook_secret")
.get_decrypted(&sighup_owner_id, "http_webhook_secret")
.await
{
// Thread-safe: Uses INJECTED_VARS mutex instead of unsafe std::env::set_var
@@ -821,7 +825,7 @@ async fn async_main() -> anyhow::Result<()> {
// Reload config (now with secrets injected into environment)
let new_config = match &sighup_settings_store_clone {
Some(store) => {
ironclaw::config::Config::from_db(store.as_ref(), "default").await
ironclaw::config::Config::from_db(store.as_ref(), &sighup_owner_id).await
}
None => ironclaw::config::Config::from_env().await,
};