Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .sce/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"integrations": {
"optional_workflows": [],
"target": [
"claude",
"opencode",
"claude",
"pi",
"codex"
]
Expand Down
4 changes: 4 additions & 0 deletions cli/src/services/auth_db/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ impl ServiceLifecycle for AuthDbLifecycle {
}

async fn setup<C: HasRepoRoot>(&self, _ctx: &C) -> Result<SetupOutcome> {
if auth_db_path()?.exists() {
return Ok(SetupOutcome::default());
}

AuthDb::new()
.await
.context("Auth DB lifecycle setup failed while initializing auth DB")?;
Expand Down
18 changes: 9 additions & 9 deletions cli/src/services/doctor/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::services::repository_identity::resolve::{
use crate::services::setup::{
config_merge, hook_merge, iter_embedded_assets_for_setup_target_with_selection,
iter_required_hook_assets, persisted_optional_workflows, repair_merge_target_asset,
EmbeddedAsset, SetupTarget,
ConcreteSetupTarget, EmbeddedAsset,
};

use super::render::integration_target_label;
Expand Down Expand Up @@ -902,7 +902,7 @@ pub(super) fn repair_merge_target_configs(
collect_claude_integration_groups(repository_root, &selected_optional_workflows);
if let Some(result) = repair_merge_target_if_mismatched(
repository_root,
SetupTarget::Claude,
ConcreteSetupTarget::Claude,
claude_asset::SETTINGS_FILE,
&claude_groups,
) {
Expand All @@ -915,7 +915,7 @@ pub(super) fn repair_merge_target_configs(
collect_opencode_integration_groups(repository_root, &selected_optional_workflows);
if let Some(result) = repair_merge_target_if_mismatched(
repository_root,
SetupTarget::OpenCode,
ConcreteSetupTarget::OpenCode,
OPENCODE_CONFIG_RELATIVE_PATH,
&opencode_groups,
) {
Expand Down Expand Up @@ -974,7 +974,7 @@ fn repair_codex_hooks_json_if_structurally_unhealthy(
Some(
match repair_merge_target_asset(
repository_root,
SetupTarget::Codex,
ConcreteSetupTarget::Codex,
CODEX_HOOKS_JSON_RELATIVE_PATH,
) {
Ok(()) => DoctorFixResultRecord {
Expand All @@ -998,7 +998,7 @@ fn repair_codex_hooks_json_if_structurally_unhealthy(

fn repair_merge_target_if_mismatched(
repository_root: &Path,
target: SetupTarget,
target: ConcreteSetupTarget,
relative_path: &str,
groups: &[IntegrationGroupHealth],
) -> Option<DoctorFixResultRecord> {
Expand Down Expand Up @@ -1864,7 +1864,7 @@ fn collect_opencode_integration_groups(
let opencode_root = repo_paths.opencode_dir();
let manifest_path = repo_paths.opencode_manifest_file();
let embedded_assets = iter_embedded_assets_for_setup_target_with_selection(
SetupTarget::OpenCode,
ConcreteSetupTarget::OpenCode,
selected_optional_workflows,
)
.collect::<Vec<_>>();
Expand Down Expand Up @@ -1952,7 +1952,7 @@ fn collect_claude_integration_groups(
let repo_paths = RepoPaths::new(repository_root);
let claude_root = repo_paths.claude_dir();
let embedded_assets = iter_embedded_assets_for_setup_target_with_selection(
SetupTarget::Claude,
ConcreteSetupTarget::Claude,
selected_optional_workflows,
)
.collect::<Vec<_>>();
Expand Down Expand Up @@ -2014,7 +2014,7 @@ fn collect_pi_integration_groups(
let repo_paths = RepoPaths::new(repository_root);
let pi_root = repo_paths.pi_dir();
let embedded_assets = iter_embedded_assets_for_setup_target_with_selection(
SetupTarget::Pi,
ConcreteSetupTarget::Pi,
selected_optional_workflows,
)
.collect::<Vec<_>>();
Expand Down Expand Up @@ -2074,7 +2074,7 @@ fn collect_codex_integration_groups(
) -> Vec<IntegrationGroupHealth> {
let codex_root = InstallTargetPaths::new(repository_root).codex_target_dir();
let embedded_assets = iter_embedded_assets_for_setup_target_with_selection(
SetupTarget::Codex,
ConcreteSetupTarget::Codex,
selected_optional_workflows,
)
.collect::<Vec<_>>();
Expand Down
15 changes: 9 additions & 6 deletions cli/src/services/parse/command_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,16 @@ fn convert_clap_command(command: cli_schema::Commands) -> Result<RuntimeCommand,
bootstrap_context,
workflow,
} => convert_setup_command(services::setup::SetupCliOptions {
help: false,
target: [
(opencode, services::setup::SetupTarget::OpenCode),
(claude, services::setup::SetupTarget::Claude),
(pi, services::setup::SetupTarget::Pi),
(codex, services::setup::SetupTarget::Codex),
(all, services::setup::SetupTarget::All),
]
.into_iter()
.find_map(|(selected, target)| selected.then_some(target)),
non_interactive,
opencode,
claude,
pi,
codex,
all,
hooks,
repo_path: repo,
bootstrap_context,
Expand Down
28 changes: 11 additions & 17 deletions cli/src/services/setup/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,15 @@ impl SetupCommand {
mode,
&setup::InquireSetupTargetPrompter,
&optional_workflow_defaults,
&setup::persisted_integration_targets(&repository_root),
setup::persisted_setup_confirmations(&repository_root),
)
.map_err(unexpected_failure)?
{
setup::SetupDispatch::Proceed {
mode: resolved_mode,
optional_workflows,
agent_trace_auto_sync,
attribution_hooks_enabled,
} => Some((
resolved_mode,
optional_workflows,
agent_trace_auto_sync,
attribution_hooks_enabled,
)),
setup::SetupDispatch::Cancelled => {
return Ok(setup::setup_cancelled_text());
}
dispatch @ setup::SetupDispatch::Proceed { .. } => Some(dispatch),
}
} else {
None
Expand Down Expand Up @@ -82,20 +74,22 @@ impl SetupCommand {
}
}

if let Some((
resolved_mode,
prompted_optional_workflows,
if let Some(setup::SetupDispatch::Proceed {
targets,
target_persistence,
optional_workflows: prompted_optional_workflows,
agent_trace_auto_sync,
attribution_hooks_enabled,
)) = setup_dispatch
}) = setup_dispatch
{
let optional_workflows = prompted_optional_workflows
.as_deref()
.or(self.request.optional_workflows.as_deref());

let setup_message = setup::run_setup_for_mode(
let setup_message = setup::run_setup_for_targets(
&repository_root,
resolved_mode,
&targets,
target_persistence,
optional_workflows,
agent_trace_auto_sync,
attribution_hooks_enabled,
Expand Down
74 changes: 36 additions & 38 deletions cli/src/services/setup/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ use crate::services::security::{ensure_directory_is_writable, redact_sensitive_t
use super::config_merge;
use super::hook_merge;
use super::{
classify_git_exit, cleanup_path_if_exists, concrete_targets_for,
embedded_assets_for_concrete_target, hook_install_recovery_guidance,
iter_embedded_assets_for_setup_target_with_selection, iter_required_hook_assets,
setup_install_recovery_guidance, EmbeddedAsset, GitExitKind, GitRepositoryResolutionError,
RequiredHookInstallResult, RequiredHookInstallStatus, RequiredHooksInstallOutcome,
SetupInstallOutcome, SetupInstallTargetResult, SetupTarget,
classify_git_exit, cleanup_path_if_exists, embedded_assets_for_concrete_target,
hook_install_recovery_guidance, iter_embedded_assets_for_setup_target_with_selection,
iter_required_hook_assets, setup_install_recovery_guidance, ConcreteSetupTarget, EmbeddedAsset,
GitExitKind, GitRepositoryResolutionError, RequiredHookInstallResult,
RequiredHookInstallStatus, RequiredHooksInstallOutcome, SetupInstallOutcome,
SetupInstallTargetResult,
};
use crate::services::default_paths;
use crate::services::default_paths::claude_asset;
Expand Down Expand Up @@ -53,20 +53,20 @@ where

pub(super) fn install_embedded_setup_assets(
repository_root: &Path,
target: SetupTarget,
targets: &[ConcreteSetupTarget],
selected_optional_workflows: &[String],
) -> Result<SetupInstallOutcome> {
install_embedded_setup_assets_with_rename(
repository_root,
target,
targets,
selected_optional_workflows,
|from, to| fs::rename(from, to),
)
}

pub(super) fn repair_merge_target_asset(
repository_root: &Path,
target: SetupTarget,
target: ConcreteSetupTarget,
relative_path: &str,
) -> Result<()> {
let asset = embedded_assets_for_concrete_target(target)
Expand All @@ -76,20 +76,26 @@ pub(super) fn repair_merge_target_asset(
format!("No embedded asset named '{relative_path}' for target {target:?}")
})?;

let install_targets = InstallTargetPaths::new(repository_root);
let destination_root = match target {
SetupTarget::OpenCode => install_targets.opencode_target_dir(),
SetupTarget::Claude => install_targets.claude_target_dir(),
SetupTarget::Pi => install_targets.pi_target_dir(),
SetupTarget::Codex => install_targets.codex_target_dir(),
SetupTarget::All => unreachable!("meta targets are expanded into concrete targets"),
};
let destination_root = concrete_target_destination_root(repository_root, target);

install_single_asset_with_rename(target, &destination_root, asset, &mut |from, to| {
fs::rename(from, to)
})
}

fn concrete_target_destination_root(
repository_root: &Path,
target: ConcreteSetupTarget,
) -> PathBuf {
let install_targets = InstallTargetPaths::new(repository_root);
match target {
ConcreteSetupTarget::OpenCode => install_targets.opencode_target_dir(),
ConcreteSetupTarget::Claude => install_targets.claude_target_dir(),
ConcreteSetupTarget::Pi => install_targets.pi_target_dir(),
ConcreteSetupTarget::Codex => install_targets.codex_target_dir(),
}
}

fn install_required_git_hooks_in_resolved_repository<F>(
resolved_repository_root: &Path,
mut rename_fn: F,
Expand Down Expand Up @@ -494,7 +500,7 @@ fn is_executable_file(path: &Path) -> Result<bool> {

pub(super) fn install_embedded_setup_assets_with_rename<F>(
repository_root: &Path,
target: SetupTarget,
targets: &[ConcreteSetupTarget],
selected_optional_workflows: &[String],
mut rename_fn: F,
) -> Result<SetupInstallOutcome>
Expand All @@ -505,7 +511,7 @@ where

let mut target_results = Vec::new();

for concrete_target in concrete_targets_for(target) {
for concrete_target in targets {
let concrete_target = *concrete_target;
let assets: Vec<&'static EmbeddedAsset> =
iter_embedded_assets_for_setup_target_with_selection(
Expand All @@ -527,23 +533,14 @@ where

fn install_assets_for_concrete_target_with_rename<F>(
repository_root: &Path,
target: SetupTarget,
target: ConcreteSetupTarget,
assets: &[&'static EmbeddedAsset],
rename_fn: &mut F,
) -> Result<SetupInstallTargetResult>
where
F: FnMut(&Path, &Path) -> io::Result<()>,
{
let install_targets = InstallTargetPaths::new(repository_root);
let destination_root = match target {
SetupTarget::OpenCode => install_targets.opencode_target_dir(),
SetupTarget::Claude => install_targets.claude_target_dir(),
SetupTarget::Pi => install_targets.pi_target_dir(),
SetupTarget::Codex => install_targets.codex_target_dir(),
SetupTarget::All => {
unreachable!("meta targets are expanded into concrete targets")
}
};
let destination_root = concrete_target_destination_root(repository_root, target);

for asset in assets {
install_single_asset_with_rename(target, &destination_root, asset, rename_fn)?;
Expand All @@ -560,7 +557,7 @@ where

fn prune_stale_assets_for_concrete_target(
destination_root: &Path,
target: SetupTarget,
target: ConcreteSetupTarget,
installed_assets: &[&'static EmbeddedAsset],
) -> Result<()> {
let installed_paths: std::collections::HashSet<&'static str> = installed_assets
Expand Down Expand Up @@ -604,20 +601,21 @@ fn remove_empty_ancestor_directories(destination_root: &Path, removed_file: &Pat
}
}

fn is_claude_settings_merge_target(target: SetupTarget, relative_path: &str) -> bool {
target == SetupTarget::Claude && relative_path == claude_asset::SETTINGS_FILE
fn is_claude_settings_merge_target(target: ConcreteSetupTarget, relative_path: &str) -> bool {
target == ConcreteSetupTarget::Claude && relative_path == claude_asset::SETTINGS_FILE
}

fn is_opencode_config_merge_target(target: SetupTarget, relative_path: &str) -> bool {
target == SetupTarget::OpenCode && relative_path == default_paths::repo_file::OPENCODE_MANIFEST
fn is_opencode_config_merge_target(target: ConcreteSetupTarget, relative_path: &str) -> bool {
target == ConcreteSetupTarget::OpenCode
&& relative_path == default_paths::repo_file::OPENCODE_MANIFEST
}

fn is_codex_hooks_merge_target(target: SetupTarget, relative_path: &str) -> bool {
target == SetupTarget::Codex && relative_path == ".codex/hooks.json"
fn is_codex_hooks_merge_target(target: ConcreteSetupTarget, relative_path: &str) -> bool {
target == ConcreteSetupTarget::Codex && relative_path == ".codex/hooks.json"
}

fn install_single_asset_with_rename<F>(
target: SetupTarget,
target: ConcreteSetupTarget,
destination_root: &Path,
asset: &'static EmbeddedAsset,
rename_fn: &mut F,
Expand Down
Loading
Loading