add Notes folder and move sync state out of knowledge

- Add knowledge/Notes/ folder created on startup, pinned to top of sidebar
- New Note/New Folder default to creating inside Notes/
- Move Granola sync state to ~/.rowboat/granola_sync_state.json
- Move Fireflies sync state to ~/.rowboat/fireflies_sync_state.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arjun 2026-03-16 23:02:29 +05:30
parent 98dfd0f159
commit 468a3a7b97
3 changed files with 16 additions and 6 deletions

View file

@ -258,10 +258,18 @@ const normalizeUsage = (usage?: Partial<LanguageModelUsage> | null): LanguageMod
} }
} }
// Sort nodes (dirs first, then alphabetically) // Pinned folders appear first in the sidebar (in this order)
const PINNED_FOLDERS = ['Notes']
// Sort nodes (dirs first, pinned folders at top, then alphabetically)
function sortNodes(nodes: TreeNode[]): TreeNode[] { function sortNodes(nodes: TreeNode[]): TreeNode[] {
return nodes.sort((a, b) => { return nodes.sort((a, b) => {
if (a.kind !== b.kind) return a.kind === 'dir' ? -1 : 1 if (a.kind !== b.kind) return a.kind === 'dir' ? -1 : 1
const aPinned = PINNED_FOLDERS.indexOf(a.name)
const bPinned = PINNED_FOLDERS.indexOf(b.name)
if (aPinned !== -1 && bPinned !== -1) return aPinned - bPinned
if (aPinned !== -1) return -1
if (bPinned !== -1) return 1
return a.name.localeCompare(b.name) return a.name.localeCompare(b.name)
}).map(node => { }).map(node => {
if (node.children) { if (node.children) {
@ -991,10 +999,12 @@ function App() {
} }
}, []) }, [])
// Ensure bases/ directory exists on startup // Ensure bases/ and knowledge/Notes/ directories exist on startup
useEffect(() => { useEffect(() => {
window.ipc.invoke('workspace:mkdir', { path: 'bases', recursive: true }) window.ipc.invoke('workspace:mkdir', { path: 'bases', recursive: true })
.catch((err: unknown) => console.error('Failed to ensure bases directory:', err)) .catch((err: unknown) => console.error('Failed to ensure bases directory:', err))
window.ipc.invoke('workspace:mkdir', { path: 'knowledge/Notes', recursive: true })
.catch((err: unknown) => console.error('Failed to ensure Notes directory:', err))
}, []) }, [])
// Load initial tree // Load initial tree
@ -3113,7 +3123,7 @@ function App() {
}, []) }, [])
const knowledgeActions = React.useMemo(() => ({ const knowledgeActions = React.useMemo(() => ({
createNote: async (parentPath: string = 'knowledge') => { createNote: async (parentPath: string = 'knowledge/Notes') => {
try { try {
let index = 0 let index = 0
let name = untitledBaseName let name = untitledBaseName
@ -3136,7 +3146,7 @@ function App() {
throw err throw err
} }
}, },
createFolder: async (parentPath: string = 'knowledge') => { createFolder: async (parentPath: string = 'knowledge/Notes') => {
try { try {
await window.ipc.invoke('workspace:mkdir', { await window.ipc.invoke('workspace:mkdir', {
path: `${parentPath}/new-folder-${Date.now()}`, path: `${parentPath}/new-folder-${Date.now()}`,

View file

@ -18,7 +18,7 @@ const GRANOLA_CLIENT_VERSION = '6.462.1';
const GRANOLA_API_BASE = 'https://api.granola.ai'; const GRANOLA_API_BASE = 'https://api.granola.ai';
const GRANOLA_CONFIG_PATH = path.join(homedir(), 'Library', 'Application Support', 'Granola', 'supabase.json'); const GRANOLA_CONFIG_PATH = path.join(homedir(), 'Library', 'Application Support', 'Granola', 'supabase.json');
const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'granola'); const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'granola');
const STATE_FILE = path.join(SYNC_DIR, 'sync_state.json'); const STATE_FILE = path.join(WorkDir, 'granola_sync_state.json');
const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes
const API_DELAY_MS = 1000; // 1 second delay between API calls const API_DELAY_MS = 1000; // 1 second delay between API calls
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit

View file

@ -8,7 +8,7 @@ import { limitEventItems } from './limit_event_items.js';
// Configuration // Configuration
const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'fireflies'); const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'fireflies');
const SYNC_INTERVAL_MS = 30 * 60 * 1000; // Check every 30 minutes (reduced from 1 minute) const SYNC_INTERVAL_MS = 30 * 60 * 1000; // Check every 30 minutes (reduced from 1 minute)
const STATE_FILE = path.join(SYNC_DIR, 'sync_state.json'); const STATE_FILE = path.join(WorkDir, 'fireflies_sync_state.json');
const LOOKBACK_DAYS = 30; // Last 1 month const LOOKBACK_DAYS = 30; // Last 1 month
const API_DELAY_MS = 2000; // 2 second delay between API calls const API_DELAY_MS = 2000; // 2 second delay between API calls
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit