perf: completely eradicate large vector allocations and state locking double-clones in main, meta, env, workspaces, and notes modules
This commit is contained in:
1 parent
6b37799cc5
commit
9476bcd649
9 files changed
+335
-108
No files matched your search
@@ -0,0 +1,61 @@
|
||||
import os
|
||||
|
||||
def fix_env_and_workspaces():
|
||||
filepath = 'server/src/handlers_v2/env.rs'
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
old_env = """ let fps = state.env_fingerprints.read();
|
||||
if let Some(fp) = fps.get(&req.namespace) {"""
|
||||
|
||||
new_env = """ let data = state.env_fingerprints.read_with(|fps| {
|
||||
fps.get(&req.namespace).cloned()
|
||||
});
|
||||
if let Some(fp) = data {"""
|
||||
|
||||
if old_env in content:
|
||||
content = content.replace(old_env, new_env)
|
||||
print('Replaced env read')
|
||||
else:
|
||||
print('Could not find old_env')
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
filepath = 'server/src/handlers_v2/workspaces.rs'
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
old_ws = """ let query = req.query.to_lowercase();
|
||||
let snippets = state.snippets.read();
|
||||
let mut results = Vec::new();
|
||||
for s in snippets {
|
||||
if contains_ignore_ascii_case(&s.name, &query)
|
||||
|| contains_ignore_ascii_case(&s.description, &query)
|
||||
|| contains_ignore_ascii_case(&s.language, &query)
|
||||
{
|
||||
results.push(s);
|
||||
}
|
||||
}
|
||||
let data = serde_json::to_string(&results).unwrap_or_default();"""
|
||||
|
||||
new_ws = """ let query = req.query.to_lowercase();
|
||||
let data = state.snippets.read_with(|snippets| {
|
||||
let results: Vec<_> = snippets.iter().filter(|s| {
|
||||
contains_ignore_ascii_case(&s.name, &query)
|
||||
|| contains_ignore_ascii_case(&s.description, &query)
|
||||
|| contains_ignore_ascii_case(&s.language, &query)
|
||||
}).cloned().collect();
|
||||
serde_json::to_string(&results).unwrap_or_default()
|
||||
});"""
|
||||
|
||||
if old_ws in content:
|
||||
content = content.replace(old_ws, new_ws)
|
||||
print('Replaced workspaces read')
|
||||
else:
|
||||
print('Could not find old_ws')
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
fix_env_and_workspaces()
|
||||
@@ -0,0 +1,60 @@
|
||||
import os
|
||||
|
||||
def fix_main_stats():
|
||||
filepath = 'server/src/main.rs'
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
old_stats = """ let (entities, relations) = {
|
||||
let graph = state_clone.get_full_graph();
|
||||
(graph.entities.len(), graph.relations.len())
|
||||
};
|
||||
let tasks = state_clone.tasks.read().len();
|
||||
let snippets = state_clone.snippets.read().len();
|
||||
let tech_debts = state_clone.tech_debts.read().len();
|
||||
let adrs = state_clone.adrs.read().len();
|
||||
|
||||
let ledger = state_clone.ledger.read().len();
|
||||
let sticky = state_clone.sticky.read().len();
|
||||
let error_fixes = state_clone.error_fixes.read().len();
|
||||
let pinned_files = state_clone.pinned_files.read().len();
|
||||
let session_summaries = state_clone.session_summaries.read().len();
|
||||
let handoff_memos = state_clone.handoff_memos.read().len();
|
||||
let env_fingerprints = state_clone.env_fingerprints.read().len();
|
||||
let env_requirements = state_clone.env_requirements.read().len();
|
||||
let milestones = state_clone.milestones.read().len();
|
||||
let environments = state_clone.environments.read().len();
|
||||
let pr_checklists = state_clone.pr_checklists.read().len();
|
||||
let gates = state_clone.gates.read().len();
|
||||
let context_workspaces = state_clone.context_workspaces.read().len();"""
|
||||
|
||||
new_stats = """ let (entities, relations) = state_clone.read_graph(|g| (g.entities.len(), g.relations.len()));
|
||||
let tasks = state_clone.tasks.read_with(|items| items.len());
|
||||
let snippets = state_clone.snippets.read_with(|items| items.len());
|
||||
let tech_debts = state_clone.tech_debts.read_with(|items| items.len());
|
||||
let adrs = state_clone.adrs.read_with(|items| items.len());
|
||||
|
||||
let ledger = state_clone.ledger.read_with(|items| items.len());
|
||||
let sticky = state_clone.sticky.read_with(|items| items.len());
|
||||
let error_fixes = state_clone.error_fixes.read_with(|items| items.len());
|
||||
let pinned_files = state_clone.pinned_files.read_with(|items| items.len());
|
||||
let session_summaries = state_clone.session_summaries.read_with(|items| items.len());
|
||||
let handoff_memos = state_clone.handoff_memos.read_with(|items| items.len());
|
||||
let env_fingerprints = state_clone.env_fingerprints.read_with(|items| items.len());
|
||||
let env_requirements = state_clone.env_requirements.read_with(|items| items.len());
|
||||
let milestones = state_clone.milestones.read_with(|items| items.len());
|
||||
let environments = state_clone.environments.read_with(|items| items.len());
|
||||
let pr_checklists = state_clone.pr_checklists.read_with(|items| items.len());
|
||||
let gates = state_clone.gates.read_with(|items| items.len());
|
||||
let context_workspaces = state_clone.context_workspaces.read_with(|items| items.len());"""
|
||||
|
||||
if old_stats in content:
|
||||
content = content.replace(old_stats, new_stats)
|
||||
print('Replaced stats reads')
|
||||
else:
|
||||
print('Could not find old_stats')
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
fix_main_stats()
|
||||
@@ -0,0 +1,111 @@
|
||||
import os
|
||||
|
||||
def fix_meta():
|
||||
filepath = 'server/src/handlers_v2/meta.rs'
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
old_omni = """ let q = req.query.to_lowercase();
|
||||
let tech_debts: Vec<_> = state
|
||||
.tech_debts
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|d| {
|
||||
req.namespace.as_ref().is_none_or(|ns| d.namespace == *ns)
|
||||
&& (contains_ignore_ascii_case(&d.description, &q)
|
||||
|| contains_ignore_ascii_case(&d.ideal_solution, &q))
|
||||
})
|
||||
.collect();
|
||||
let memos: Vec<_> = state
|
||||
.handoff_memos
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| {
|
||||
req.namespace.as_ref().is_none_or(|ns| m.namespace == *ns)
|
||||
&& contains_ignore_ascii_case(&m.content, &q)
|
||||
})
|
||||
.collect();
|
||||
let error_fixes: Vec<_> = state
|
||||
.error_fixes
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|f| {
|
||||
contains_ignore_ascii_case(&f.signature, &q)
|
||||
|| contains_ignore_ascii_case(&f.solution, &q)
|
||||
})
|
||||
.collect();"""
|
||||
|
||||
new_omni = """ let q = req.query.to_lowercase();
|
||||
let tech_debts = state.tech_debts.read_with(|debts| {
|
||||
debts.iter().filter(|d| {
|
||||
req.namespace.as_ref().is_none_or(|ns| d.namespace == *ns)
|
||||
&& (contains_ignore_ascii_case(&d.description, &q)
|
||||
|| contains_ignore_ascii_case(&d.ideal_solution, &q))
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});
|
||||
let memos = state.handoff_memos.read_with(|memos| {
|
||||
memos.iter().filter(|m| {
|
||||
req.namespace.as_ref().is_none_or(|ns| m.namespace == *ns)
|
||||
&& contains_ignore_ascii_case(&m.content, &q)
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});
|
||||
let error_fixes = state.error_fixes.read_with(|fixes| {
|
||||
fixes.iter().filter(|f| {
|
||||
contains_ignore_ascii_case(&f.signature, &q)
|
||||
|| contains_ignore_ascii_case(&f.solution, &q)
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});"""
|
||||
|
||||
if old_omni in content:
|
||||
content = content.replace(old_omni, new_omni)
|
||||
print('Replaced omni_search vecs')
|
||||
else:
|
||||
print('Could not find old_omni')
|
||||
|
||||
old_health = """ let active_tasks = state
|
||||
.tasks
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|t| t.status != "done")
|
||||
.count();
|
||||
let unresolved_debt = state
|
||||
.tech_debts
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|d| d.namespace == req.namespace && !d.is_resolved)
|
||||
.count();
|
||||
let unread_memos = state
|
||||
.handoff_memos
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| m.namespace == req.namespace)
|
||||
.count();
|
||||
let active_milestones = state
|
||||
.milestones
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| m.namespace == req.namespace && m.status != "done")
|
||||
.count();
|
||||
let remaining_checklists = state
|
||||
.pr_checklists
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|c| c.namespace == req.namespace)
|
||||
.count();"""
|
||||
|
||||
new_health = """ let active_tasks = state.tasks.read_with(|tasks| tasks.iter().filter(|t| t.status != "done").count());
|
||||
let unresolved_debt = state.tech_debts.read_with(|debts| debts.iter().filter(|d| d.namespace == req.namespace && !d.is_resolved).count());
|
||||
let unread_memos = state.handoff_memos.read_with(|memos| memos.iter().filter(|m| m.namespace == req.namespace).count());
|
||||
let active_milestones = state.milestones.read_with(|milestones| milestones.iter().filter(|m| m.namespace == req.namespace && m.status != "done").count());
|
||||
let remaining_checklists = state.pr_checklists.read_with(|checklists| checklists.iter().filter(|c| c.namespace == req.namespace).count());"""
|
||||
|
||||
if old_health in content:
|
||||
content = content.replace(old_health, new_health)
|
||||
print('Replaced health counters')
|
||||
else:
|
||||
print('Could not find old_health')
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
fix_meta()
|
||||
@@ -0,0 +1,40 @@
|
||||
import os
|
||||
|
||||
def fix_notes():
|
||||
filepath = 'server/src/handlers_v2/notes.rs'
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
old_standup = """ let tasks = state
|
||||
.tasks
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|t| t.updated_at >= cutoff)
|
||||
.collect::<Vec<_>>();
|
||||
let changes = state
|
||||
.ledger
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|c| c.timestamp >= cutoff)
|
||||
.collect::<Vec<_>>();
|
||||
let summaries = state
|
||||
.session_summaries
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|s| s.namespace == req.namespace && s.timestamp >= cutoff)
|
||||
.collect::<Vec<_>>();"""
|
||||
|
||||
new_standup = """ let tasks = state.tasks.read_with(|items| items.iter().filter(|t| t.updated_at >= cutoff).cloned().collect::<Vec<_>>());
|
||||
let changes = state.ledger.read_with(|items| items.iter().filter(|c| c.timestamp >= cutoff).cloned().collect::<Vec<_>>());
|
||||
let summaries = state.session_summaries.read_with(|items| items.iter().filter(|s| s.namespace == req.namespace && s.timestamp >= cutoff).cloned().collect::<Vec<_>>());"""
|
||||
|
||||
if old_standup in content:
|
||||
content = content.replace(old_standup, new_standup)
|
||||
print('Replaced standup in notes.rs')
|
||||
else:
|
||||
print('Could not find old_standup in notes.rs')
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
fix_notes()
|
||||
@@ -61,9 +61,11 @@ impl McpTool for ReadEnvFingerprintHandler {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
let req: ReadEnvFingerprintTool =
|
||||
serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let fps = state.env_fingerprints.read();
|
||||
if let Some(fp) = fps.get(&req.namespace) {
|
||||
let data = serde_json::to_string(fp).unwrap_or_default();
|
||||
let data = state.env_fingerprints.read_with(|fps| {
|
||||
fps.get(&req.namespace).cloned()
|
||||
});
|
||||
if let Some(fp) = data {
|
||||
let data = serde_json::to_string(&fp).unwrap_or_default();
|
||||
Ok(data.to_string())
|
||||
} else {
|
||||
Ok("{}".to_string())
|
||||
@@ -164,3 +166,4 @@ impl McpTool for GetEnvironmentDetailsHandler {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -368,60 +368,57 @@ impl McpTool for OmniSearchHandler {
|
||||
}
|
||||
}
|
||||
});
|
||||
for t in state.tasks.read() {
|
||||
state.tasks.read_with(|all_tasks| {
|
||||
for t in all_tasks {
|
||||
if matches
|
||||
.iter()
|
||||
.any(|(id, typ, _, _, _)| id == &t.id && typ == "task")
|
||||
{
|
||||
tasks.push(t);
|
||||
tasks.push(t.clone());
|
||||
}
|
||||
}
|
||||
for s in state.snippets.read() {
|
||||
});
|
||||
state.snippets.read_with(|all_snippets| {
|
||||
for s in all_snippets {
|
||||
if matches
|
||||
.iter()
|
||||
.any(|(id, typ, _, _, _)| id == &s.name && typ == "snippet")
|
||||
{
|
||||
snippets.push(s);
|
||||
snippets.push(s.clone());
|
||||
}
|
||||
}
|
||||
for a in state.adrs.read() {
|
||||
});
|
||||
state.adrs.read_with(|all_adrs| {
|
||||
for a in all_adrs {
|
||||
if matches
|
||||
.iter()
|
||||
.any(|(id, typ, _, _, _)| id == &a.id && typ == "adr")
|
||||
{
|
||||
adrs.push(a);
|
||||
adrs.push(a.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let q = req.query.to_lowercase();
|
||||
let tech_debts: Vec<_> = state
|
||||
.tech_debts
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|d| {
|
||||
let tech_debts = state.tech_debts.read_with(|debts| {
|
||||
debts.iter().filter(|d| {
|
||||
req.namespace.as_ref().is_none_or(|ns| d.namespace == *ns)
|
||||
&& (contains_ignore_ascii_case(&d.description, &q)
|
||||
|| contains_ignore_ascii_case(&d.ideal_solution, &q))
|
||||
})
|
||||
.collect();
|
||||
let memos: Vec<_> = state
|
||||
.handoff_memos
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| {
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});
|
||||
let memos = state.handoff_memos.read_with(|memos| {
|
||||
memos.iter().filter(|m| {
|
||||
req.namespace.as_ref().is_none_or(|ns| m.namespace == *ns)
|
||||
&& contains_ignore_ascii_case(&m.content, &q)
|
||||
})
|
||||
.collect();
|
||||
let error_fixes: Vec<_> = state
|
||||
.error_fixes
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|f| {
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});
|
||||
let error_fixes = state.error_fixes.read_with(|fixes| {
|
||||
fixes.iter().filter(|f| {
|
||||
contains_ignore_ascii_case(&f.signature, &q)
|
||||
|| contains_ignore_ascii_case(&f.solution, &q)
|
||||
})
|
||||
.collect();
|
||||
}).cloned().collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let report = serde_json::json!({
|
||||
"knowledge_graph": kg.entities,
|
||||
@@ -453,36 +450,11 @@ impl McpTool for GetProjectHealthHandler {
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
let req: GetProjectHealthTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let active_tasks = state
|
||||
.tasks
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|t| t.status != "done")
|
||||
.count();
|
||||
let unresolved_debt = state
|
||||
.tech_debts
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|d| d.namespace == req.namespace && !d.is_resolved)
|
||||
.count();
|
||||
let unread_memos = state
|
||||
.handoff_memos
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| m.namespace == req.namespace)
|
||||
.count();
|
||||
let active_milestones = state
|
||||
.milestones
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|m| m.namespace == req.namespace && m.status != "done")
|
||||
.count();
|
||||
let remaining_checklists = state
|
||||
.pr_checklists
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|c| c.namespace == req.namespace)
|
||||
.count();
|
||||
let active_tasks = state.tasks.read_with(|tasks| tasks.iter().filter(|t| t.status != "done").count());
|
||||
let unresolved_debt = state.tech_debts.read_with(|debts| debts.iter().filter(|d| d.namespace == req.namespace && !d.is_resolved).count());
|
||||
let unread_memos = state.handoff_memos.read_with(|memos| memos.iter().filter(|m| m.namespace == req.namespace).count());
|
||||
let active_milestones = state.milestones.read_with(|milestones| milestones.iter().filter(|m| m.namespace == req.namespace && m.status != "done").count());
|
||||
let remaining_checklists = state.pr_checklists.read_with(|checklists| checklists.iter().filter(|c| c.namespace == req.namespace).count());
|
||||
|
||||
let report = serde_json::json!({
|
||||
"active_tasks": active_tasks,
|
||||
@@ -498,3 +470,4 @@ impl McpTool for GetProjectHealthHandler {
|
||||
use crate::handlers_v2::utils::*;
|
||||
|
||||
|
||||
|
||||
@@ -254,24 +254,9 @@ impl McpTool for GenerateStandupReportHandler {
|
||||
.unwrap_or_default()
|
||||
.as_secs()
|
||||
.saturating_sub(req.hours_lookback * 3600);
|
||||
let tasks = state
|
||||
.tasks
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|t| t.updated_at >= cutoff)
|
||||
.collect::<Vec<_>>();
|
||||
let changes = state
|
||||
.ledger
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|c| c.timestamp >= cutoff)
|
||||
.collect::<Vec<_>>();
|
||||
let summaries = state
|
||||
.session_summaries
|
||||
.read()
|
||||
.into_iter()
|
||||
.filter(|s| s.namespace == req.namespace && s.timestamp >= cutoff)
|
||||
.collect::<Vec<_>>();
|
||||
let tasks = state.tasks.read_with(|items| items.iter().filter(|t| t.updated_at >= cutoff).cloned().collect::<Vec<_>>());
|
||||
let changes = state.ledger.read_with(|items| items.iter().filter(|c| c.timestamp >= cutoff).cloned().collect::<Vec<_>>());
|
||||
let summaries = state.session_summaries.read_with(|items| items.iter().filter(|s| s.namespace == req.namespace && s.timestamp >= cutoff).cloned().collect::<Vec<_>>());
|
||||
let report = serde_json::json!({ "tasks_updated": tasks, "code_changes": changes, "session_summaries": summaries });
|
||||
Ok(report.to_string())
|
||||
}
|
||||
|
||||
@@ -147,17 +147,14 @@ impl McpTool for SearchSnippetsHandler {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
let req: SearchSnippetsTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let query = req.query.to_lowercase();
|
||||
let snippets = state.snippets.read();
|
||||
let mut results = Vec::new();
|
||||
for s in snippets {
|
||||
if contains_ignore_ascii_case(&s.name, &query)
|
||||
let data = state.snippets.read_with(|snippets| {
|
||||
let results: Vec<_> = snippets.iter().filter(|s| {
|
||||
contains_ignore_ascii_case(&s.name, &query)
|
||||
|| contains_ignore_ascii_case(&s.description, &query)
|
||||
|| contains_ignore_ascii_case(&s.language, &query)
|
||||
{
|
||||
results.push(s);
|
||||
}
|
||||
}
|
||||
let data = serde_json::to_string(&results).unwrap_or_default();
|
||||
}).cloned().collect();
|
||||
serde_json::to_string(&results).unwrap_or_default()
|
||||
});
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
+18
-21
@@ -355,28 +355,25 @@ async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::error::E
|
||||
get({
|
||||
let state_clone = app_state.handler.state.clone();
|
||||
move || async move {
|
||||
let (entities, relations) = {
|
||||
let graph = state_clone.get_full_graph();
|
||||
(graph.entities.len(), graph.relations.len())
|
||||
};
|
||||
let tasks = state_clone.tasks.read().len();
|
||||
let snippets = state_clone.snippets.read().len();
|
||||
let tech_debts = state_clone.tech_debts.read().len();
|
||||
let adrs = state_clone.adrs.read().len();
|
||||
let (entities, relations) = state_clone.read_graph(|g| (g.entities.len(), g.relations.len()));
|
||||
let tasks = state_clone.tasks.read_with(|items| items.len());
|
||||
let snippets = state_clone.snippets.read_with(|items| items.len());
|
||||
let tech_debts = state_clone.tech_debts.read_with(|items| items.len());
|
||||
let adrs = state_clone.adrs.read_with(|items| items.len());
|
||||
|
||||
let ledger = state_clone.ledger.read().len();
|
||||
let sticky = state_clone.sticky.read().len();
|
||||
let error_fixes = state_clone.error_fixes.read().len();
|
||||
let pinned_files = state_clone.pinned_files.read().len();
|
||||
let session_summaries = state_clone.session_summaries.read().len();
|
||||
let handoff_memos = state_clone.handoff_memos.read().len();
|
||||
let env_fingerprints = state_clone.env_fingerprints.read().len();
|
||||
let env_requirements = state_clone.env_requirements.read().len();
|
||||
let milestones = state_clone.milestones.read().len();
|
||||
let environments = state_clone.environments.read().len();
|
||||
let pr_checklists = state_clone.pr_checklists.read().len();
|
||||
let gates = state_clone.gates.read().len();
|
||||
let context_workspaces = state_clone.context_workspaces.read().len();
|
||||
let ledger = state_clone.ledger.read_with(|items| items.len());
|
||||
let sticky = state_clone.sticky.read_with(|items| items.len());
|
||||
let error_fixes = state_clone.error_fixes.read_with(|items| items.len());
|
||||
let pinned_files = state_clone.pinned_files.read_with(|items| items.len());
|
||||
let session_summaries = state_clone.session_summaries.read_with(|items| items.len());
|
||||
let handoff_memos = state_clone.handoff_memos.read_with(|items| items.len());
|
||||
let env_fingerprints = state_clone.env_fingerprints.read_with(|items| items.len());
|
||||
let env_requirements = state_clone.env_requirements.read_with(|items| items.len());
|
||||
let milestones = state_clone.milestones.read_with(|items| items.len());
|
||||
let environments = state_clone.environments.read_with(|items| items.len());
|
||||
let pr_checklists = state_clone.pr_checklists.read_with(|items| items.len());
|
||||
let gates = state_clone.gates.read_with(|items| items.len());
|
||||
let context_workspaces = state_clone.context_workspaces.read_with(|items| items.len());
|
||||
|
||||
axum::Json(serde_json::json!({
|
||||
"entities": entities,
|
||||
|
||||
Reference in new issue
Block a user