Skip to content
Closed
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
76 changes: 76 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ CLIPPY := "$(RUSTBIN)cargo-clippy"
LLVM_PROFDATA := $(shell xcrun --find llvm-profdata 2>/dev/null)
LLVM_COV := $(shell xcrun --find llvm-cov 2>/dev/null)

.PHONY: check fmt fmt-check lint test deny machete purity ui-lint ui-check coverage hooks deps qa qa-release tasks
.PHONY: check fmt fmt-check lint test deny machete purity ui-lint ui-check ui-test coverage hooks deps qa qa-release tasks

check: fmt-check lint purity test deny ui-lint ui-check ## all gates (matches CI)
check: fmt-check lint purity test deny ui-lint ui-check ui-test ## all gates (matches CI)

fmt: ; $(FMT) --all
fmt-check: ; $(FMT) --all --check
Expand All @@ -27,6 +27,7 @@ purity: ; ./scripts/check-core-purity.sh
tasks: ; ./scripts/check-tasks.sh $(ARGS)
ui-lint: ; pnpm exec biome ci .
ui-check: ; pnpm run check
ui-test: ; pnpm test
coverage: ; LLVM_PROFDATA="$(LLVM_PROFDATA)" LLVM_COV="$(LLVM_COV)" cargo llvm-cov --package mlt-core --fail-under-lines 80
hooks: ; lefthook install
# Install/refresh dependencies THROUGH Socket Firewall (blocks malware at fetch, any depth).
Expand Down
3 changes: 3 additions & 0 deletions crates/adapters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ dirs = "5"
# In-process Mutex for the consent cache. parking_lot (already in the tree via tauri) gives
# poison-free guards, so lock sites read as locking, not error handling.
parking_lot = "0.12"
# Read-only access to Oh My Pi's per-profile SQLite credential store to discover Codex logins.
# `bundled` compiles SQLite in, so there is no system-libsqlite dependency on any platform.
rusqlite = { version = "0.32", features = ["bundled"] }

# OS keychain for OUR secrets (refreshed tokens), per-OS backend so the workspace builds
# cross-platform (incl. Linux/Windows CI). Runtime keychain access is only exercised by the
Expand Down
61 changes: 61 additions & 0 deletions crates/adapters/examples/accounts_live.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Live end-to-end check: discover every per-account login on this machine (Codex + Claude
//! Code, from the Oh My Pi store and vendor CLIs, deduped) and print each account's usage
//! snapshot through its provider's real strategy. NOT a CI test (hits the network).
//!
//! cargo run -p mlt-adapters --example accounts_live
use mlt_adapters::{
claude_account_strategy, codex_strategy, discovered_accounts, FileIdentityStore,
};
use mlt_core::domain::ProviderId;
use mlt_core::providers::{FetchContext, FetchStrategy};
use mlt_core::sources::account_source_id;
use std::sync::Arc;

#[tokio::main]
async fn main() {
let accounts = discovered_accounts();
if accounts.is_empty() {
eprintln!("no Codex/Claude logins found (checked Oh My Pi profiles and the vendor CLIs)");
std::process::exit(1);
}
println!("discovered {} account(s):", accounts.len());
for a in &accounts {
let who = a.email.as_deref().unwrap_or(&a.account_id);
println!(" - [{}] {who} [{}]", a.base.as_str(), a.origin);
}

let identity = Arc::new(FileIdentityStore::load(
std::env::temp_dir().join("mlt-accounts-live-identity.json"),
));
for a in &accounts {
let ctx = FetchContext {
provider: ProviderId::new(account_source_id(a.base.as_str(), &a.account_id)),
};
let who = a.email.as_deref().unwrap_or(&a.account_id);
// Route to the provider's strategy the same way the app's fetch_for does.
let result = match a.base.as_str() {
"codex" => {
codex_strategy(&a.account_id, identity.clone())
.fetch(&ctx)
.await
}
"claude-code" => {
claude_account_strategy(&a.account_id, identity.clone())
.fetch(&ctx)
.await
}
other => {
eprintln!("# {who}: no strategy wired for base {other}");
continue;
}
};
match result {
Ok(snapshot) => println!(
"\n# [{}] {who}\n{}",
a.base.as_str(),
serde_json::to_string_pretty(&snapshot).unwrap()
),
Err(e) => eprintln!("\n# [{}] {who}: usage fetch failed: {e}", a.base.as_str()),
}
}
}
Loading