Skip to content
This repository was archived by the owner on Apr 11, 2026. It is now read-only.

Commit a200d6f

Browse files
authored
Merge pull request #24 from z23cc/fn-18-merge-crates
refactor(flowctl): merge 4 crates into 2 (core + cli)
2 parents 99574d0 + 00f9278 commit a200d6f

38 files changed

Lines changed: 619 additions & 1457 deletions

flowctl/Cargo.lock

Lines changed: 0 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flowctl/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
resolver = "2"
33
members = [
44
"crates/flowctl-core",
5-
"crates/flowctl-db",
6-
"crates/flowctl-service",
75
"crates/flowctl-cli",
86
]
97

@@ -56,8 +54,6 @@ trycmd = "0.15"
5654

5755
# Internal crate references
5856
flowctl-core = { path = "crates/flowctl-core" }
59-
flowctl-db = { path = "crates/flowctl-db" }
60-
flowctl-service = { path = "crates/flowctl-service" }
6157

6258
# ── Shared lint configuration ────────────────────────────────────────
6359
[workspace.lints.clippy]

flowctl/crates/flowctl-cli/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ path = "src/main.rs"
1212

1313
[dependencies]
1414
flowctl-core = { workspace = true }
15-
flowctl-db = { workspace = true }
16-
flowctl-service = { workspace = true }
1715
serde = { workspace = true }
1816
serde_json = { workspace = true }
1917
anyhow = { workspace = true }
@@ -34,5 +32,3 @@ trycmd = { workspace = true }
3432
tempfile = "3"
3533
serde_json = { workspace = true }
3634
flowctl-core = { workspace = true }
37-
flowctl-db = { workspace = true }
38-
flowctl-service = { workspace = true }

flowctl/crates/flowctl-cli/src/commands/admin/init.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ pub fn cmd_init(json: bool) {
8585
}
8686

8787
// Ensure FlowStore dirs are ready
88-
let store = flowctl_db::FlowStore::new(flow_dir.clone());
89-
if let Err(e) = store.ensure_dirs() {
88+
if let Err(e) = flowctl_core::json_store::ensure_dirs(&flow_dir) {
9089
eprintln!("warning: failed to ensure store dirs: {e}");
9190
}
9291

flowctl/crates/flowctl-cli/src/commands/admin/status.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,8 +726,7 @@ pub fn cmd_doctor(json_mode: bool, workflow: bool) {
726726

727727
// Check 7: stale file locks
728728
{
729-
let store = flowctl_db::FlowStore::new(flow_dir.clone());
730-
match store.locks().list() {
729+
match flowctl_core::json_store::locks_read(&flow_dir) {
731730
Ok(locks) if !locks.is_empty() => {
732731
checks.push(json!({"name": "stale_locks", "status": "warn", "message": format!("{} file lock(s) active — verify with 'flowctl lock-check'", locks.len())}));
733732
}

flowctl/crates/flowctl-cli/src/commands/approval.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use clap::Subcommand;
88
use serde_json::Value;
99

1010
use flowctl_core::approvals::{ApprovalKind, ApprovalStatus, CreateApprovalRequest};
11-
use flowctl_service::approvals::FileApprovalStore;
11+
use flowctl_core::approvals::FileApprovalStore;
1212

1313
use crate::output::{error_exit, json_output};
1414

@@ -80,8 +80,7 @@ pub fn dispatch(cmd: &ApprovalCmd, json: bool) {
8080

8181
fn open_local_store() -> FileApprovalStore {
8282
let flow_dir = get_flow_dir();
83-
let store = flowctl_db::FlowStore::new(flow_dir);
84-
FileApprovalStore::new(store)
83+
FileApprovalStore::new(flow_dir)
8584
}
8685

8786
// ── Payload parsing ─────────────────────────────────────────────────

flowctl/crates/flowctl-cli/src/commands/gap.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use serde_json::json;
1010
use crate::output::{error_exit, json_output, pretty_output};
1111

1212
use flowctl_core::id::is_epic_id;
13-
use flowctl_db::{FlowStore, GapEntry};
13+
use flowctl_core::json_store::{self, GapEntry};
1414

1515
use super::helpers::get_flow_dir;
1616

@@ -112,8 +112,8 @@ fn validate_epic(_json: bool, epic_id: &str) {
112112
error_exit(&format!("Epic not found: {}", epic_id));
113113
}
114114

115-
fn gap_store() -> FlowStore {
116-
FlowStore::new(get_flow_dir())
115+
fn gap_flow_dir() -> std::path::PathBuf {
116+
get_flow_dir()
117117
}
118118

119119
// ── Commands ───────────────────────────────────────────────────────
@@ -126,10 +126,9 @@ fn cmd_gap_add(
126126
source: &str,
127127
) {
128128
validate_epic(json_mode, epic_id);
129-
let store = gap_store();
130-
let gap_store = store.gaps();
129+
let flow_dir = gap_flow_dir();
131130

132-
let mut gaps = gap_store.read(epic_id).unwrap_or_default();
131+
let mut gaps = json_store::gaps_read(&flow_dir, epic_id).unwrap_or_default();
133132

134133
// Check for existing gap with same capability (idempotent)
135134
let cap_lower = capability.trim().to_lowercase();
@@ -166,7 +165,7 @@ fn cmd_gap_add(
166165
resolved: false,
167166
});
168167

169-
if let Err(e) = gap_store.write(epic_id, &gaps) {
168+
if let Err(e) = json_store::gaps_write(&flow_dir, epic_id, &gaps) {
170169
error_exit(&format!("Failed to add gap: {e}"));
171170
}
172171

@@ -190,8 +189,8 @@ fn cmd_gap_add(
190189

191190
fn cmd_gap_list(json_mode: bool, epic_id: &str, status_filter: Option<&str>) {
192191
validate_epic(json_mode, epic_id);
193-
let store = gap_store();
194-
let gaps = store.gaps().read(epic_id).unwrap_or_default();
192+
let flow_dir = gap_flow_dir();
193+
let gaps = json_store::gaps_read(&flow_dir, epic_id).unwrap_or_default();
195194

196195
let filtered: Vec<&GapEntry> = gaps.iter().filter(|g| {
197196
match status_filter {
@@ -244,9 +243,8 @@ fn cmd_gap_resolve(
244243
_evidence: &str,
245244
) {
246245
validate_epic(json_mode, epic_id);
247-
let store = gap_store();
248-
let gap_st = store.gaps();
249-
let mut gaps = gap_st.read(epic_id).unwrap_or_default();
246+
let flow_dir = gap_flow_dir();
247+
let mut gaps = json_store::gaps_read(&flow_dir, epic_id).unwrap_or_default();
250248

251249
if let Some(direct_id) = gap_id_direct {
252250
let gap_id: u32 = direct_id
@@ -259,7 +257,7 @@ fn cmd_gap_resolve(
259257
error_exit(&format!("Gap {} not found", gap_id));
260258
}
261259

262-
gap_st.write(epic_id, &gaps).unwrap_or_else(|e| {
260+
json_store::gaps_write(&flow_dir, epic_id, &gaps).unwrap_or_else(|e| {
263261
error_exit(&format!("Failed to resolve gap: {e}"));
264262
});
265263

@@ -281,7 +279,7 @@ fn cmd_gap_resolve(
281279
error_exit(&format!("Gap for capability '{}' not found", cap));
282280
}
283281

284-
gap_st.write(epic_id, &gaps).unwrap_or_else(|e| {
282+
json_store::gaps_write(&flow_dir, epic_id, &gaps).unwrap_or_else(|e| {
285283
error_exit(&format!("Failed to resolve gap: {e}"));
286284
});
287285

@@ -301,8 +299,8 @@ fn cmd_gap_resolve(
301299

302300
fn cmd_gap_check(json_mode: bool, epic_id: &str) {
303301
validate_epic(json_mode, epic_id);
304-
let store = gap_store();
305-
let all_gaps = store.gaps().read(epic_id).unwrap_or_default();
302+
let flow_dir = gap_flow_dir();
303+
let all_gaps = json_store::gaps_read(&flow_dir, epic_id).unwrap_or_default();
306304

307305
let open_blocking: Vec<&GapEntry> = all_gaps
308306
.iter()

flowctl/crates/flowctl-cli/src/commands/helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), std::io::Error> {
149149
/// Returns the number of mutations applied. Calls `error_exit` on failure.
150150
pub fn apply_changes(flow_dir: &Path, changes: &flowctl_core::changes::Changes) -> usize {
151151
use crate::output::error_exit;
152-
use flowctl_service::changes::ChangesApplier;
152+
use flowctl_core::changes::ChangesApplier;
153153

154154
if changes.is_empty() {
155155
return 0;

flowctl/crates/flowctl-cli/src/commands/log.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use serde_json::json;
1010
use crate::output::{error_exit, json_output, pretty_output};
1111
use super::helpers::get_flow_dir;
1212

13-
use flowctl_db::FlowStore;
13+
use flowctl_core::json_store;
1414

1515
#[derive(Subcommand, Debug)]
1616
pub enum LogCmd {
@@ -65,7 +65,6 @@ fn cmd_log_decision(
6565
task_id: Option<&str>,
6666
) {
6767
let flow_dir = get_flow_dir();
68-
let store = FlowStore::new(flow_dir);
6968

7069
let epic = epic_id.unwrap_or("_global");
7170

@@ -80,7 +79,7 @@ fn cmd_log_decision(
8079
"timestamp": chrono::Utc::now().to_rfc3339(),
8180
});
8281

83-
if let Err(e) = store.events().append(&event.to_string()) {
82+
if let Err(e) = json_store::events_append(&flow_dir, &event.to_string()) {
8483
error_exit(&format!("Failed to log decision: {e}"));
8584
}
8685

@@ -100,9 +99,8 @@ fn cmd_log_decision(
10099

101100
fn cmd_log_decisions(json_mode: bool, epic_id: Option<&str>, limit: usize) {
102101
let flow_dir = get_flow_dir();
103-
let store = FlowStore::new(flow_dir);
104102

105-
let all_lines = store.events().read_all().unwrap_or_else(|e| {
103+
let all_lines = json_store::events_read_all(&flow_dir).unwrap_or_else(|e| {
106104
error_exit(&format!("Failed to query decisions: {e}"));
107105
});
108106

flowctl/crates/flowctl-cli/src/commands/outputs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Outputs commands: write, list, show.
22
//!
3-
//! Thin CLI wrapper over `flowctl_service::outputs::OutputsStore`. Provides
3+
//! Thin CLI wrapper over `flowctl_core::outputs::OutputsStore`. Provides
44
//! a lightweight narrative handoff layer at `.flow/outputs/<task-id>.md` that
55
//! workers populate in Phase 9 and read during Phase 2 re-anchor.
66
@@ -11,7 +11,7 @@ use clap::Subcommand;
1111
use serde_json::json;
1212

1313
use flowctl_core::id::is_task_id;
14-
use flowctl_service::outputs::OutputsStore;
14+
use flowctl_core::outputs::OutputsStore;
1515

1616
use crate::output::{error_exit, json_output};
1717

0 commit comments

Comments
 (0)