← back to dperhar__research-inbox

Function bodies 92 total

All specs Real LLM only Function bodies
App function · typescript · L16-L153 (138 LOC)
src/App.tsx
export default function App() {
  const { view, loadItems, loadSettings, loadTags, showToast, settings } = useStore();
  const [onboarded, setOnboarded] = useState<boolean | null>(null);

  // Check if onboarding was completed
  useEffect(() => {
    const done = localStorage.getItem("ri-onboarded");
    setOnboarded(done === "true");
    loadItems();
    loadSettings();
    loadTags();
  }, []);

  useEffect(() => {
    if (settings?.language) setLanguage(settings.language);
  }, [settings?.language]);

  const completeOnboarding = () => {
    localStorage.setItem("ri-onboarded", "true");
    setOnboarded(true);
  };

  // ⇧⌘S capture — tries selected text first (no clipboard touch), falls back to clipboard
  useEffect(() => {
    const unlisten = listen<string>("capture-triggered", async (event) => {
      try {
        let appName = "Clipboard";
        let windowTitle = "";
        let urlFromTitle: string | null = null;
        let selectedText: string | null = null;

        try 
CaptureOverlay function · typescript · L14-L242 (229 LOC)
src/components/CaptureOverlay.tsx
export default function CaptureOverlay() {
  const [state, setState] = useState<OverlayState>({ mode: "idle" });
  const dismissTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
  const sourceAppRef = useRef(""); // remember source app for refocus

  const autoDismiss = (source: string) => {
    if (dismissTimer.current) clearTimeout(dismissTimer.current);
    dismissTimer.current = setTimeout(async () => {
      getCurrentWindow().hide();
      setState({ mode: "idle" });
      // Refocus source app
      if (source) {
        invoke("refocus_app", { appName: source }).catch(() => {});
      }
    }, 4000);
  };

  // Text + image capture event from Rust
  useEffect(() => {
    const unlisten = listen<string>("capture-triggered", async (event) => {
      try {
        let appName = "Clipboard";
        let selectedText: string | null = null;
        let imagePaths: string[] = [];

        try {
          if (event.payload) {
            const data = JSON.parse(even
InboxPanel function · typescript · L9-L178 (170 LOC)
src/components/InboxPanel.tsx
export default function InboxPanel() {
  const { items, selectedIds, setView, showArchived, setShowArchived, loadItems, selectAll, clearSelection, archiveSelected, searchQuery } = useStore();

  useEffect(() => {
    loadItems(showArchived);
  }, [showArchived]);

  const todayCount = items.filter((i) => {
    const d = new Date(i.created_at);
    const now = new Date();
    return d.toDateString() === now.toDateString();
  }).length;

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.metaKey && e.key === "a") {
      e.preventDefault();
      selectAll();
    }
    if (e.metaKey && e.key === "Backspace") {
      e.preventDefault();
      archiveSelected();
    }
  };

  return (
    <div className="flex flex-col h-full" onKeyDown={handleKeyDown} tabIndex={0}>
      {/* Title bar: drag + capture buttons + close */}
      <div className="flex items-center px-3 pt-2 pb-1 gap-1" data-tauri-drag-region>
        <span className="text-xs font-semibold text-[var(--text-secondary
appBadgeColor function · typescript · L15-L18 (4 LOC)
src/components/ItemCard.tsx
function appBadgeColor(appName: string): string {
  const hash = Array.from(appName).reduce((acc, c) => acc * 31 + c.charCodeAt(0), 0);
  return APP_BADGE_COLORS[Math.abs(hash) % APP_BADGE_COLORS.length];
}
ItemCard function · typescript · L24-L176 (153 LOC)
src/components/ItemCard.tsx
export default function ItemCard({ item }: ItemCardProps) {
  const { selectedIds, toggleSelect, expandedId, setExpanded, deleteItem, updateItemTags, showToast } = useStore();
  const [showContext, setShowContext] = useState(false);
  const isSelected = selectedIds.has(item.id);
  const isExpanded = expandedId === item.id;

  const time = new Date(item.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
  const preview = item.content.slice(0, 120);
  const isImage = item.content_type === "image";
  const colorIndex = (name: string) => {
    const hash = Array.from(name).reduce((acc, c) => acc * 31 + c.charCodeAt(0), 0);
    return Math.abs(hash) % 8;
  };

  const handleCopy = async () => {
    await writeText(item.content);
    showToast("Copied");
  };

  const handleArchive = async () => {
    await api.updateItem(item.id, null, null, true);
    useStore.getState().loadItems(useStore.getState().showArchived);
  };

  return (
    <div
      className={`relati
Onboarding function · typescript · L8-L165 (158 LOC)
src/components/Onboarding.tsx
export default function Onboarding({ onComplete }: OnboardingProps) {
  const [step, setStep] = useState<"welcome" | "accessibility" | "done">("welcome");
  const [axGranted, setAxGranted] = useState(false);
  const [checking, setChecking] = useState(false);

  const checkAx = useCallback(async () => {
    setChecking(true);
    try {
      const granted = await invoke<boolean>("check_accessibility");
      setAxGranted(granted);
      // Don't auto-skip — user must confirm they enabled BOTH permissions
    } catch {
      setAxGranted(false);
    }
    setChecking(false);
  }, [step]);

  // Poll for accessibility permission every 2s when on that step
  useEffect(() => {
    if (step !== "accessibility") return;
    checkAx();
    const interval = setInterval(checkAx, 2000);
    return () => clearInterval(interval);
  }, [step, checkAx]);

  const openSettings = async () => {
    await invoke("open_accessibility_settings");
  };

  if (step === "welcome") {
    return (
      <div cla
PackEditor function · typescript · L11-L195 (185 LOC)
src/components/PackEditor.tsx
export default function PackEditor() {
  const { editingPack, setEditingPack, showToast, loadPacks, items: allItems } = useStore();
  const [title, setTitle] = useState(editingPack?.title || "");
  const [description, setDescription] = useState(editingPack?.description || "");
  const [constraints, setConstraints] = useState(editingPack?.constraints || "");
  const [questions, setQuestions] = useState(editingPack?.questions || "");
  const [format, setFormat] = useState<ExportFormat>((editingPack?.export_format as ExportFormat) || "markdown");
  const [itemIds, setItemIds] = useState<string[]>(editingPack?.item_ids || []);
  const [packItems, setPackItems] = useState<CaptureItem[]>([]);

  useEffect(() => {
    // Load the actual items for the pack
    const loadPackItems = async () => {
      const loaded = await api.listItems(0, 200, false, null, null);
      const filtered = loaded.filter((i) => itemIds.includes(i.id));
      // Maintain order from itemIds
      const ordered = item
Repobility · severity-and-effort ranking · https://repobility.com
PacksList function · typescript · L7-L89 (83 LOC)
src/components/PacksList.tsx
export default function PacksList() {
  const { packs, loadPacks, setEditingPack, deletePack, setView, showToast } = useStore();

  useEffect(() => {
    loadPacks();
  }, []);

  const handleExport = async (id: string, format: string) => {
    const exported = await api.exportPack(id, format);
    await writeText(exported);
    showToast(`✓ ${t("pack_copied", { count: 0 })}`);
  };

  return (
    <div className="flex flex-col h-full">
      {/* Header */}
      <div className="px-3 py-2 border-b border-[var(--border)] flex items-center gap-2">
        <button
          onClick={() => setView("inbox")}
          className="px-2 py-0.5 rounded text-[11px] text-[var(--text-secondary)] hover:bg-[var(--bg-secondary)]"
        >
          {t("inbox")}
        </button>
        <button
          className="px-2 py-0.5 rounded text-[11px] font-medium bg-[var(--accent)] text-white"
        >
          {t("packs")}
        </button>
      </div>

      {/* Pack list */}
      <div className="f
SearchBar function · typescript · L5-L67 (63 LOC)
src/components/SearchBar.tsx
export default function SearchBar() {
  const { searchQuery, setSearchQuery, searchItems, loadItems, showArchived } = useStore();
  const [localQuery, setLocalQuery] = useState(searchQuery);
  const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => {
      setSearchQuery(localQuery);
      if (localQuery.trim()) {
        searchItems(localQuery);
      } else {
        loadItems(showArchived);
      }
    }, 150);
    return () => clearTimeout(timerRef.current);
  }, [localQuery]);

  // Auto-focus search on panel open (Maccy pattern: search-on-open)
  useEffect(() => {
    inputRef.current?.focus();
    const handleFocus = () => inputRef.current?.focus();
    window.addEventListener("focus", handleFocus);
    return () => window.removeEventListener("focus", handleFocus);
  }, []);

  useEffect(() => {
    const handl
Settings function · typescript · L7-L145 (139 LOC)
src/components/Settings.tsx
export default function Settings() {
  const { settings, loadSettings, setView, showToast } = useStore();
  const [local, setLocal] = useState<AppSettings | null>(null);

  useEffect(() => {
    if (settings) setLocal({ ...settings });
  }, [settings]);

  if (!local) return null;

  const update = <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => {
    setLocal({ ...local, [key]: value });
  };

  const handleSave = async () => {
    try {
      await api.updateSettings(local);
      await loadSettings();
      showToast(`✓ ${t("save")}`);
      setView("inbox");
    } catch {
      showToast("Error saving settings");
    }
  };

  return (
    <div className="flex flex-col h-full">
      {/* Header */}
      <div className="px-3 py-2 border-b border-[var(--border)] flex items-center gap-2">
        <button onClick={() => setView("inbox")} className="text-[var(--text-secondary)] hover:text-[var(--text)]">
          <svg className="w-4 h-4" fill="none" stroke="currentColo
SettingRow function · typescript · L147-L154 (8 LOC)
src/components/Settings.tsx
function SettingRow({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div>
      <div className="text-[11px] text-[var(--text-secondary)] mb-1 font-medium">{label}</div>
      {children}
    </div>
  );
}
TagInput function · typescript · L11-L98 (88 LOC)
src/components/TagInput.tsx
export default function TagInput({ value, onChange }: TagInputProps) {
  const [input, setInput] = useState("");
  const [suggestions, setSuggestions] = useState<{ name: string; color_index: number }[]>([]);
  const [showSuggestions, setShowSuggestions] = useState(false);
  const { tags, loadTags } = useStore();
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (input.length > 0) {
      loadTags(input);
      setShowSuggestions(true);
    } else {
      setShowSuggestions(false);
    }
  }, [input]);

  useEffect(() => {
    setSuggestions(tags.filter((tag) => !value.includes(tag.name)));
  }, [tags, value]);

  const addTag = (tagName: string) => {
    const normalized = tagName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").slice(0, 30);
    if (normalized && !value.includes(normalized)) {
      onChange([...value, normalized]);
    }
    setInput("");
    setShowSuggestions(false);
  };

  const removeTag = (tagName: string) => {
    onCh
Toast function · typescript · L3-L14 (12 LOC)
src/components/Toast.tsx
export default function Toast() {
  const { toast } = useStore();
  if (!toast.visible) return null;

  return (
    <div className="fixed top-3 left-1/2 -translate-x-1/2 z-50">
      <div className="bg-gray-900 text-white px-4 py-2.5 rounded-lg shadow-lg text-sm font-medium max-w-[340px] truncate">
        {toast.message}
      </div>
    </div>
  );
}
setLanguage function · typescript · L8-L10 (3 LOC)
src/lib/i18n.ts
export function setLanguage(lang: string) {
  currentLang = lang;
}
t function · typescript · L12-L21 (10 LOC)
src/lib/i18n.ts
export function t(key: string, params?: Record<string, string | number>): string {
  const dict = translations[currentLang] || translations.en;
  let text = dict[key] || translations.en[key] || key;
  if (params) {
    for (const [k, v] of Object.entries(params)) {
      text = text.replace(`{${k}}`, String(v));
    }
  }
  return text;
}
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
getLanguage function · typescript · L23-L25 (3 LOC)
src/lib/i18n.ts
export function getLanguage(): string {
  return currentLang;
}
main function · rust · L1-L3 (3 LOC)
src-tauri/build.rs
fn main() {
  tauri_build::build()
}
row_to_item function · rust · L9-L27 (19 LOC)
src-tauri/src/commands.rs
fn row_to_item(row: &rusqlite::Row) -> rusqlite::Result<CaptureItem> {
    let tags_str: String = row.get(6)?;
    let tags: Vec<String> = serde_json::from_str(&tags_str).unwrap_or_default();
    let is_archived: i32 = row.get(8)?;
    Ok(CaptureItem {
        id: row.get(0)?,
        content: row.get(1)?,
        content_type: row.get(2)?,
        source_app: row.get(3)?,
        source_url: row.get(4)?,
        source_title: row.get(5)?,
        tags,
        char_count: row.get(7)?,
        is_archived: is_archived != 0,
        created_at: row.get(9)?,
        updated_at: row.get(10)?,
    })
}
row_to_tag function · rust · L28-L36 (9 LOC)
src-tauri/src/commands.rs
fn row_to_tag(row: &rusqlite::Row) -> rusqlite::Result<Tag> {
    Ok(Tag {
        name: row.get(0)?,
        use_count: row.get(1)?,
        last_used_at: row.get(2)?,
        color_index: row.get(3)?,
    })
}
row_to_pack function · rust · L37-L52 (16 LOC)
src-tauri/src/commands.rs
fn row_to_pack(row: &rusqlite::Row) -> rusqlite::Result<ContextPack> {
    let item_ids_str: String = row.get(5)?;
    let item_ids: Vec<String> = serde_json::from_str(&item_ids_str).unwrap_or_default();
    Ok(ContextPack {
        id: row.get(0)?,
        title: row.get(1)?,
        description: row.get(2)?,
        constraints: row.get(3)?,
        questions: row.get(4)?,
        item_ids,
        export_format: row.get(6)?,
        created_at: row.get(7)?,
        updated_at: row.get(8)?,
    })
}
capture_item function · rust · L57-L92 (36 LOC)
src-tauri/src/commands.rs
pub fn capture_item(
    db: State<'_, Database>,
    content: String,
    source_app: String,
    source_url: Option<String>,
    source_title: Option<String>,
    tags: Vec<String>,
) -> Result<CaptureItem, String> {

    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let id = Uuid::new_v4().to_string();
    let now = Utc::now().to_rfc3339();
    let char_count = content.len() as i64;
    let tags_json = serde_json::to_string(&tags).unwrap_or_else(|_| "[]".to_string());

    conn.execute(
        "INSERT INTO items (id, content, content_type, source_app, source_url, source_title, tags, char_count, is_archived, created_at, updated_at)
         VALUES (?1, ?2, 'text', ?3, ?4, ?5, ?6, ?7, 0, ?8, ?9)",
        params![id, content, source_app, source_url, source_title, tags_json, char_count, now, now],
    ).map_err(|e| e.to_string())?;

    for tag in &tags {
        let color_index = tag_color_index(tag);
        conn.execute(
            "INSERT INTO tags (name, use_count, 
capture_screenshot function · rust · L95-L169 (75 LOC)
src-tauri/src/commands.rs
pub fn capture_screenshot(
    db: State<'_, Database>,
    tags: Vec<String>,
) -> Result<CaptureItem, String> {
    // Get data dir for storing images
    let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
    let images_dir = PathBuf::from(&home).join(".research-inbox").join("images");
    std::fs::create_dir_all(&images_dir).map_err(|e| e.to_string())?;

    let img_id = Uuid::new_v4().to_string();
    let img_path = images_dir.join(format!("{}.png", img_id));
    let img_path_str = img_path.to_string_lossy().to_string();

    // Get foreground app BEFORE screencapture (which steals focus)
    let app_info = crate::source_detect::get_foreground_app();

    // Interactive screen region capture (macOS)
    let status = Command::new("screencapture")
        .args(["-i", &img_path_str])
        .status()
        .map_err(|e| e.to_string())?;

    if !status.success() || !img_path.exists() {
        return Err("Screenshot cancelled or failed".to_string());
    }

    
check_duplicate function · rust · L172-L185 (14 LOC)
src-tauri/src/commands.rs
pub fn check_duplicate(
    db: State<'_, Database>,
    content: String,
) -> Result<bool, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    // Check if identical content exists in last 100 items
    let exists: bool = conn.query_row(
        "SELECT COUNT(*) > 0 FROM (SELECT content FROM items WHERE is_archived = 0 ORDER BY created_at DESC LIMIT 100) WHERE content = ?1",
        params![content],
        |row| row.get(0),
    ).unwrap_or(false);

    Ok(exists)
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
get_ocr_binary_path function · rust · L186-L210 (25 LOC)
src-tauri/src/commands.rs
fn get_ocr_binary_path() -> String {
    let exe = std::env::current_exe().unwrap_or_default();
    let exe_dir = exe.parent().unwrap_or(std::path::Path::new("."));

    // macOS .app bundle: Contents/MacOS/../Resources/scripts/ocr
    let resources = exe_dir.parent().unwrap_or(exe_dir).join("Resources").join("scripts").join("ocr");
    if resources.exists() {
        return resources.to_string_lossy().to_string();
    }

    // Next to binary
    let beside_exe = exe_dir.join("ocr");
    if beside_exe.exists() {
        return beside_exe.to_string_lossy().to_string();
    }

    // Development: cargo manifest dir
    let dev_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("scripts").join("ocr");
    if dev_path.exists() {
        return dev_path.to_string_lossy().to_string();
    }

    "ocr".to_string()
}
list_items function · rust · L213-L245 (33 LOC)
src-tauri/src/commands.rs
pub fn list_items(
    db: State<'_, Database>,
    offset: u32,
    limit: u32,
    archived: bool,
    tag_filter: Option<String>,
    source_filter: Option<String>,
) -> Result<Vec<CaptureItem>, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let archived_val: i32 = if archived { 1 } else { 0 };

    let mut sql = String::from(
        "SELECT id, content, content_type, source_app, source_url, source_title, tags, char_count, is_archived, created_at, updated_at FROM items WHERE is_archived = ?"
    );
    let mut params_vec: Vec<Box<dyn rusqlite::types::ToSql>> = vec![Box::new(archived_val)];

    if let Some(ref tag) = tag_filter {
        sql.push_str(" AND tags LIKE ?");
        params_vec.push(Box::new(format!("%\"{}\"%" , tag)));
    }
    if let Some(ref source) = source_filter {
        sql.push_str(" AND LOWER(source_app) = LOWER(?)");
        params_vec.push(Box::new(source.clone()));
    }
    sql.push_str(" ORDER BY created_at DESC LIMIT ? OFFSET ?
search_items function · rust · L248-L307 (60 LOC)
src-tauri/src/commands.rs
pub fn search_items(
    db: State<'_, Database>,
    query: String,
    limit: u32,
) -> Result<Vec<CaptureItem>, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;

    if query.trim().is_empty() {
        let mut stmt = conn.prepare(
            "SELECT id, content, content_type, source_app, source_url, source_title, tags, char_count, is_archived, created_at, updated_at FROM items WHERE is_archived = 0 ORDER BY created_at DESC LIMIT ?1"
        ).map_err(|e| e.to_string())?;
        let rows = stmt.query_map(params![limit], row_to_item).map_err(|e| e.to_string())?;
        return Ok(rows.filter_map(|r| r.ok()).collect());
    }

    // Parse special filters
    let mut fts_parts: Vec<String> = Vec::new();
    let mut extra_where: Vec<String> = Vec::new();

    for part in query.split_whitespace() {
        if let Some(tag) = part.strip_prefix('#') {
            extra_where.push(format!("i.tags LIKE '%\"{}\"'", tag.replace('\'', "''").to_lowercase()));
        } els
update_item function · rust · L310-L348 (39 LOC)
src-tauri/src/commands.rs
pub fn update_item(
    db: State<'_, Database>,
    id: String,
    content: Option<String>,
    tags: Option<Vec<String>>,
    is_archived: Option<bool>,
) -> Result<CaptureItem, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let now = Utc::now().to_rfc3339();

    if let Some(ref c) = content {
        conn.execute(
            "UPDATE items SET content = ?1, char_count = ?2, updated_at = ?3 WHERE id = ?4",
            params![c, c.len() as i64, now, id],
        ).map_err(|e| e.to_string())?;
    }
    if let Some(ref t) = tags {
        let tags_json = serde_json::to_string(t).unwrap_or_else(|_| "[]".to_string());
        conn.execute("UPDATE items SET tags = ?1, updated_at = ?2 WHERE id = ?3", params![tags_json, now, id])
            .map_err(|e| e.to_string())?;
        for tag in t {
            let ci = tag_color_index(tag);
            conn.execute(
                "INSERT INTO tags (name, use_count, last_used_at, color_index) VALUES (?1, 1, ?2, ?3)
delete_item function · rust · L351-L355 (5 LOC)
src-tauri/src/commands.rs
pub fn delete_item(db: State<'_, Database>, id: String) -> Result<(), String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    conn.execute("DELETE FROM items WHERE id = ?1", params![id]).map_err(|e| e.to_string())?;
    Ok(())
}
list_tags function · rust · L360-L382 (23 LOC)
src-tauri/src/commands.rs
pub fn list_tags(
    db: State<'_, Database>,
    prefix: Option<String>,
    limit: u32,
) -> Result<Vec<Tag>, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;

    let items: Vec<Tag> = if let Some(ref p) = prefix {
        let search = format!("{}%", p.to_lowercase());
        let mut stmt = conn.prepare(
            "SELECT name, use_count, last_used_at, color_index FROM tags WHERE name LIKE ?1 ORDER BY use_count DESC LIMIT ?2"
        ).map_err(|e| e.to_string())?;
        let rows = stmt.query_map(params![search, limit], row_to_tag).map_err(|e| e.to_string())?;
        rows.filter_map(|r| r.ok()).collect()
    } else {
        let mut stmt = conn.prepare(
            "SELECT name, use_count, last_used_at, color_index FROM tags ORDER BY use_count DESC LIMIT ?1"
        ).map_err(|e| e.to_string())?;
        let rows = stmt.query_map(params![limit], row_to_tag).map_err(|e| e.to_string())?;
        rows.filter_map(|r| r.ok()).collect()
    };
    Ok(items)
}
create_pack function · rust · L387-L411 (25 LOC)
src-tauri/src/commands.rs
pub fn create_pack(
    db: State<'_, Database>,
    title: String,
    description: Option<String>,
    constraints: Option<String>,
    questions: Option<String>,
    item_ids: Vec<String>,
    export_format: String,
) -> Result<ContextPack, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let id = Uuid::new_v4().to_string();
    let now = Utc::now().to_rfc3339();
    let item_ids_json = serde_json::to_string(&item_ids).unwrap_or_else(|_| "[]".to_string());

    conn.execute(
        "INSERT INTO packs (id, title, description, constraints_text, questions, item_ids, export_format, created_at, updated_at)
         VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
        params![id, title, description, constraints, questions, item_ids_json, export_format, now, now],
    ).map_err(|e| e.to_string())?;

    Ok(ContextPack {
        id, title, description, constraints, questions, item_ids, export_format,
        created_at: now.clone(), updated_at: now,
    })
}
update_pack function · rust · L414-L451 (38 LOC)
src-tauri/src/commands.rs
pub fn update_pack(
    db: State<'_, Database>,
    id: String,
    title: Option<String>,
    description: Option<String>,
    constraints: Option<String>,
    questions: Option<String>,
    item_ids: Option<Vec<String>>,
    export_format: Option<String>,
) -> Result<ContextPack, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let now = Utc::now().to_rfc3339();

    if let Some(ref t) = title {
        conn.execute("UPDATE packs SET title = ?1, updated_at = ?2 WHERE id = ?3", params![t, now, id]).map_err(|e| e.to_string())?;
    }
    if let Some(ref d) = description {
        conn.execute("UPDATE packs SET description = ?1, updated_at = ?2 WHERE id = ?3", params![d, now, id]).map_err(|e| e.to_string())?;
    }
    if let Some(ref c) = constraints {
        conn.execute("UPDATE packs SET constraints_text = ?1, updated_at = ?2 WHERE id = ?3", params![c, now, id]).map_err(|e| e.to_string())?;
    }
    if let Some(ref q) = questions {
        conn.execute("UPD
Repobility · open methodology · https://repobility.com/research/
list_packs function · rust · L454-L461 (8 LOC)
src-tauri/src/commands.rs
pub fn list_packs(db: State<'_, Database>, limit: u32) -> Result<Vec<ContextPack>, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let mut stmt = conn.prepare(
        "SELECT id, title, description, constraints_text, questions, item_ids, export_format, created_at, updated_at FROM packs ORDER BY updated_at DESC LIMIT ?1"
    ).map_err(|e| e.to_string())?;
    let rows = stmt.query_map(params![limit], row_to_pack).map_err(|e| e.to_string())?;
    Ok(rows.filter_map(|r| r.ok()).collect())
}
export_pack function · rust · L464-L483 (20 LOC)
src-tauri/src/commands.rs
pub fn export_pack(db: State<'_, Database>, id: String, format: String) -> Result<String, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;

    let mut stmt = conn.prepare(
        "SELECT id, title, description, constraints_text, questions, item_ids, export_format, created_at, updated_at FROM packs WHERE id = ?1"
    ).map_err(|e| e.to_string())?;
    let pack = stmt.query_row(params![id], row_to_pack).map_err(|e| e.to_string())?;

    let mut items: Vec<CaptureItem> = Vec::new();
    for item_id in &pack.item_ids {
        let mut item_stmt = conn.prepare(
            "SELECT id, content, content_type, source_app, source_url, source_title, tags, char_count, is_archived, created_at, updated_at FROM items WHERE id = ?1"
        ).map_err(|e| e.to_string())?;
        if let Ok(item) = item_stmt.query_row(params![item_id], row_to_item) {
            items.push(item);
        }
    }

    Ok(format_pack(&pack, &items, &format))
}
delete_pack function · rust · L486-L490 (5 LOC)
src-tauri/src/commands.rs
pub fn delete_pack(db: State<'_, Database>, id: String) -> Result<(), String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    conn.execute("DELETE FROM packs WHERE id = ?1", params![id]).map_err(|e| e.to_string())?;
    Ok(())
}
get_settings function · rust · L495-L518 (24 LOC)
src-tauri/src/commands.rs
pub fn get_settings(db: State<'_, Database>) -> Result<AppSettings, String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let mut settings = AppSettings::default();
    let mut stmt = conn.prepare("SELECT key, value FROM settings").map_err(|e| e.to_string())?;
    let rows = stmt.query_map([], |row| {
        Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
    }).map_err(|e| e.to_string())?;

    for row in rows.flatten() {
        match row.0.as_str() {
            "capture_hotkey" => settings.capture_hotkey = row.1,
            "panel_hotkey" => settings.panel_hotkey = row.1,
            "quick_tag_on_capture" => settings.quick_tag_on_capture = row.1 == "true",
            "default_export_format" => settings.default_export_format = row.1,
            "max_capture_size_kb" => settings.max_capture_size_kb = row.1.parse().unwrap_or(50),
            "launch_at_login" => settings.launch_at_login = row.1 == "true",
            "theme" => settings.theme = row.1,
update_settings function · rust · L521-L541 (21 LOC)
src-tauri/src/commands.rs
pub fn update_settings(db: State<'_, Database>, settings: AppSettings) -> Result<(), String> {
    let conn = db.conn.lock().map_err(|e| e.to_string())?;
    let pairs = vec![
        ("capture_hotkey", settings.capture_hotkey),
        ("panel_hotkey", settings.panel_hotkey),
        ("quick_tag_on_capture", settings.quick_tag_on_capture.to_string()),
        ("default_export_format", settings.default_export_format),
        ("max_capture_size_kb", settings.max_capture_size_kb.to_string()),
        ("launch_at_login", settings.launch_at_login.to_string()),
        ("theme", settings.theme),
        ("language", settings.language),
        ("data_location", settings.data_location),
    ];
    for (key, value) in pairs {
        conn.execute(
            "INSERT INTO settings (key, value) VALUES (?1, ?2) ON CONFLICT(key) DO UPDATE SET value = ?2",
            params![key, value],
        ).map_err(|e| e.to_string())?;
    }
    Ok(())
}
get_foreground_app_cmd function · rust · L546-L548 (3 LOC)
src-tauri/src/commands.rs
pub fn get_foreground_app_cmd() -> Result<AppInfo, String> {
    Ok(crate::source_detect::get_foreground_app())
}
check_accessibility function · rust · L552-L567 (16 LOC)
src-tauri/src/commands.rs
pub fn check_accessibility() -> bool {
    #[cfg(target_os = "macos")]
    {
        use std::process::Command;
        let output = Command::new("osascript")
            .arg("-e")
            .arg(r#"tell application "System Events" to keystroke ""#)
            .output();
        match output {
            Ok(o) => !String::from_utf8_lossy(&o.stderr).contains("not allowed"),
            Err(_) => false,
        }
    }
    #[cfg(not(target_os = "macos"))]
    { true }
}
refocus_app function · rust · L571-L581 (11 LOC)
src-tauri/src/commands.rs
pub fn refocus_app(app_name: String) {
    #[cfg(target_os = "macos")]
    {
        use std::process::Command;
        let script = format!(
            r#"tell application "{}" to activate"#,
            app_name.replace('"', r#"\""#)
        );
        let _ = Command::new("osascript").arg("-e").arg(&script).spawn();
    }
}
Repobility · severity-and-effort ranking · https://repobility.com
open_input_monitoring_settings function · rust · L585-L593 (9 LOC)
src-tauri/src/commands.rs
pub fn open_input_monitoring_settings() {
    #[cfg(target_os = "macos")]
    {
        use std::process::Command;
        let _ = Command::new("open")
            .arg("x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent")
            .spawn();
    }
}
open_accessibility_settings function · rust · L597-L605 (9 LOC)
src-tauri/src/commands.rs
pub fn open_accessibility_settings() {
    #[cfg(target_os = "macos")]
    {
        use std::process::Command;
        let _ = Command::new("open")
            .arg("x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility")
            .spawn();
    }
}
trigger_text_capture function · rust · L609-L614 (6 LOC)
src-tauri/src/commands.rs
pub fn trigger_text_capture(app_handle: tauri::AppHandle) -> Result<(), String> {
    let app_info = crate::source_detect::get_foreground_app();
    let payload = serde_json::to_string(&app_info).unwrap_or_default();
    let result = app_handle.emit("overlay-capture-text", payload).map_err(|e: tauri::Error| e.to_string());
    result
}
trigger_screenshot_capture function · rust · L618-L621 (4 LOC)
src-tauri/src/commands.rs
pub fn trigger_screenshot_capture(app_handle: tauri::AppHandle) -> Result<(), String> {
    let result = app_handle.emit("overlay-capture-screenshot", ()).map_err(|e: tauri::Error| e.to_string());
    result
}
tag_color_index function · rust · L624-L628 (5 LOC)
src-tauri/src/commands.rs
fn tag_color_index(tag: &str) -> i64 {
    let hash: u32 = tag.bytes().fold(0u32, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u32));
    (hash % 8) as i64
}
fmt_time function · rust · L631-L642 (12 LOC)
src-tauri/src/commands.rs
fn fmt_time(iso: &str) -> String {
    let months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
    if iso.len() >= 16 {
        let month_idx: usize = iso[5..7].parse().unwrap_or(1);
        let day: &str = &iso[8..10];
        let time: &str = &iso[11..16];
        let month = months.get(month_idx.wrapping_sub(1)).unwrap_or(&"???");
        format!("{} {}, {}", month, day.trim_start_matches('0'), time)
    } else {
        iso.to_string()
    }
}
fmt_source function · rust · L645-L650 (6 LOC)
src-tauri/src/commands.rs
fn fmt_source(app: &str, url: Option<&str>, title: Option<&str>) -> String {
    let mut parts = vec![app.to_string()];
    if let Some(u) = url { if !u.is_empty() { parts.push(u.to_string()); } }
    if let Some(t) = title { if !t.is_empty() { parts.push(t.to_string()); } }
    parts.join(" | ")
}
format_pack function · rust · L651-L718 (68 LOC)
src-tauri/src/commands.rs
pub fn format_pack(pack: &ContextPack, items: &[CaptureItem], format: &str) -> String {
    let title = if pack.title.is_empty() { "Context Pack" } else { &pack.title };
    let desc = pack.description.as_deref().unwrap_or("");
    let constraints = pack.constraints.as_deref().unwrap_or("");
    let questions = pack.questions.as_deref().unwrap_or("");
    let date = if pack.created_at.len() >= 10 { &pack.created_at[..10] } else { &pack.created_at };

    match format {
        "claude" => {
            let mut out = String::from("<context>\n");
            if !title.is_empty() { out.push_str(&format!("<title>{}</title>\n", title)); }
            out.push_str(&format!("<summary>{}</summary>\n\n<evidence count=\"{}\">\n", desc, items.len()));
            for item in items {
                let mut attrs = format!("source=\"{}\" date=\"{}\"", item.source_app, fmt_time(&item.created_at));
                if let Some(ref u) = item.source_url { if !u.is_empty() { attrs.push_str(&format!(" u
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
test_fmt_time function · rust · L725-L729 (5 LOC)
src-tauri/src/commands.rs
    fn test_fmt_time() {
        assert_eq!(fmt_time("2026-03-28T12:44:30.973176+00:00"), "Mar 28, 12:44");
        assert_eq!(fmt_time("2026-01-05T09:01:00Z"), "Jan 5, 09:01");
        assert_eq!(fmt_time("short"), "short");
    }
test_fmt_source_full function · rust · L732-L735 (4 LOC)
src-tauri/src/commands.rs
    fn test_fmt_source_full() {
        let s = fmt_source("Chrome", Some("https://example.com"), Some("My Page"));
        assert_eq!(s, "Chrome | https://example.com | My Page");
    }
test_fmt_source_no_url function · rust · L738-L741 (4 LOC)
src-tauri/src/commands.rs
    fn test_fmt_source_no_url() {
        let s = fmt_source("Telegram", None, Some("Chat with Bob"));
        assert_eq!(s, "Telegram | Chat with Bob");
    }
page 1 / 2next ›