1814 lines
52 KiB
TypeScript
1814 lines
52 KiB
TypeScript
/**
|
|
* Mock Tauri invoke for browser testing.
|
|
* When running outside Tauri (e.g. in Chrome via localhost:5173),
|
|
* this provides realistic test data so the UI can be verified visually.
|
|
*/
|
|
|
|
import type { VaultEntry, GitCommit, ModifiedFile, Settings } from './types'
|
|
|
|
// --- Vault API detection (for reading real files in browser dev mode) ---
|
|
let vaultApiAvailable: boolean | null = null
|
|
|
|
async function checkVaultApi(): Promise<boolean> {
|
|
if (vaultApiAvailable !== null) return vaultApiAvailable
|
|
try {
|
|
const res = await fetch('/api/vault/ping', { signal: AbortSignal.timeout(500) })
|
|
vaultApiAvailable = res.ok
|
|
} catch {
|
|
vaultApiAvailable = false
|
|
}
|
|
console.info(`[mock-tauri] Vault API available: ${vaultApiAvailable}`)
|
|
return vaultApiAvailable
|
|
}
|
|
|
|
const MOCK_CONTENT: Record<string, string> = {
|
|
'/Users/luca/Laputa/project/26q1-laputa-app.md': `---
|
|
title: Build Laputa App
|
|
is_a: Project
|
|
status: Active
|
|
owner: Luca Rossi
|
|
tags: [Tauri, React, TypeScript, CodeMirror]
|
|
tools: [Vite, Vitest, Playwright]
|
|
belongs_to:
|
|
- "[[quarter/q1-2026]]"
|
|
related_to:
|
|
- "[[topic/software-development]]"
|
|
---
|
|
|
|
# Build Laputa App
|
|
|
|
## Text Formatting
|
|
This paragraph has **bold text**, *italic text*, ***bold italic***, ~~strikethrough~~, and \`inline code\`. Here's a [regular link](https://example.com) and a wiki-link to [[Matteo Cellini]].
|
|
|
|
## Headings
|
|
|
|
### Third Level Heading
|
|
Content under H3.
|
|
|
|
#### Fourth Level Heading
|
|
Content under H4.
|
|
|
|
## Lists
|
|
|
|
### Bullet Lists (Nested)
|
|
- First level item — this is a top-level bullet point
|
|
- Second level item — indented one level
|
|
- Third level item — indented two levels
|
|
- Another third level item with longer text that wraps to multiple lines to test alignment
|
|
- Back to second level
|
|
- Another first level item
|
|
- With a nested child
|
|
- Final first level item
|
|
|
|
### Numbered Lists
|
|
1. Step one — do this first
|
|
2. Step two — then do this
|
|
3. Step three — finally this
|
|
1. Sub-step 3a
|
|
2. Sub-step 3b
|
|
|
|
### Checkboxes
|
|
- [x] Completed task with strikethrough
|
|
- [x] Another done item
|
|
- [ ] Pending task — needs attention
|
|
- [ ] Future task with **bold** text inside
|
|
|
|
### Mixed Nesting
|
|
- Top level bullet
|
|
- Nested bullet
|
|
- Deep nested bullet
|
|
- Back to second
|
|
- Another top level
|
|
- With child
|
|
|
|
## Block Quotes
|
|
> This is a blockquote. It should have a left border and distinct styling.
|
|
> It can span multiple lines and contain **formatting**.
|
|
|
|
## Code Blocks
|
|
\`\`\`typescript
|
|
interface VaultEntry {
|
|
path: string;
|
|
title: string;
|
|
isA: string;
|
|
status: string | null;
|
|
}
|
|
|
|
function loadVault(path: string): VaultEntry[] {
|
|
// Load all markdown files from the vault
|
|
return entries.filter(e => e.isA !== 'Note');
|
|
}
|
|
\`\`\`
|
|
|
|
\`\`\`yaml
|
|
title: Some Title
|
|
is_a: Project
|
|
status: Active
|
|
\`\`\`
|
|
|
|
## Tables
|
|
| Feature | Status | Priority |
|
|
|---------|--------|----------|
|
|
| Editor | Done | High |
|
|
| Inspector | Done | High |
|
|
| Git Integration | Done | Medium |
|
|
| Mobile App | Planned | Low |
|
|
|
|
## Horizontal Rule
|
|
|
|
---
|
|
|
|
## Wiki-Links
|
|
See [[Stock Screener — EMA200 Wick Bounce]] for the experiment approach.
|
|
Contact [[Matteo Cellini]] for sponsorship data.
|
|
Link to [[Grow Newsletter]] responsibility.
|
|
|
|
## Paragraphs & Spacing
|
|
This is a normal paragraph with enough text to test line wrapping and spacing between elements. The paragraph should have comfortable line height and spacing from the heading above.
|
|
|
|
And this is a second paragraph to verify inter-paragraph spacing is correct. Good typography requires consistent vertical rhythm throughout the document.
|
|
`,
|
|
'/Users/luca/Laputa/responsibility/grow-newsletter.md': `---
|
|
title: Grow Newsletter
|
|
is_a: Responsibility
|
|
status: Active
|
|
owner: Luca Rossi
|
|
---
|
|
|
|
# Grow Newsletter
|
|
|
|
## Purpose
|
|
Build a sustainable audience through high-quality weekly essays on **engineering leadership**, **AI**, and **personal systems**.
|
|
|
|
## Key Metrics
|
|
- Subscriber count (target: 100k by Q2 2026)
|
|
- Open rate (target: > 50%)
|
|
- Click-through rate
|
|
|
|
## Current Strategy
|
|
1. Publish one essay per week — Tuesday morning
|
|
2. Promote via Twitter/X threads
|
|
3. Cross-post to LinkedIn with native formatting
|
|
4. Guest posts on other newsletters monthly
|
|
|
|
## Procedures
|
|
- [[Write Weekly Essays]] — the core writing workflow
|
|
- Monthly audience analysis and topic planning
|
|
|
|
## Notes
|
|
The newsletter is the *engine* that drives everything else — sponsorships, consulting leads, and brand building.
|
|
`,
|
|
'/Users/luca/Laputa/responsibility/manage-sponsorships.md': `---
|
|
title: Manage Sponsorships
|
|
is_a: Responsibility
|
|
status: Active
|
|
owner: Matteo Cellini
|
|
---
|
|
|
|
# Manage Sponsorships
|
|
|
|
## Overview
|
|
Revenue stream from newsletter sponsorships. [[Matteo Cellini]] handles day-to-day operations.
|
|
|
|
## Process
|
|
1. Inbound leads via sponsorship page
|
|
2. Qualification call
|
|
3. Proposal and negotiation
|
|
4. Schedule and deliver
|
|
5. Report results to sponsor
|
|
|
|
## Metrics
|
|
- Monthly revenue
|
|
- Close rate
|
|
- Repeat sponsor rate
|
|
`,
|
|
'/Users/luca/Laputa/procedure/write-weekly-essays.md': `---
|
|
title: Write Weekly Essays
|
|
is_a: Procedure
|
|
status: Active
|
|
owner: Luca Rossi
|
|
cadence: Weekly
|
|
belongs_to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
---
|
|
|
|
# Write Weekly Essays
|
|
|
|
## Schedule
|
|
- **Monday**: Pick topic, outline
|
|
- **Tuesday**: First draft
|
|
- **Wednesday**: Edit and polish
|
|
- **Thursday**: Schedule for Tuesday send
|
|
|
|
## Writing Guidelines
|
|
- 1500-2500 words
|
|
- One clear takeaway
|
|
- Use *real examples* from personal experience
|
|
- Include actionable advice, not just theory
|
|
|
|
### Checklist
|
|
- [ ] Pick a topic from the backlog
|
|
- [ ] Write outline with 3-5 sections
|
|
- [x] Set up newsletter template
|
|
- [x] Configure email scheduling
|
|
- [ ] Review analytics from last issue
|
|
|
|
### Nested Topics
|
|
- Content strategy for growing the newsletter audience through organic channels, referrals, and high-quality evergreen content that people want to share with their engineering teams
|
|
- Newsletter growth and subscriber acquisition including all the different channels we use to attract new readers to the publication
|
|
- Organic subscribers from search, Twitter, and word of mouth — these are the highest quality subscribers with the best retention rates over time
|
|
- Paid acquisition through Facebook ads and newsletter cross-promotions with other engineering publications in the space
|
|
- Social media cross-posting
|
|
- Technical writing
|
|
- Code examples
|
|
- Architecture diagrams
|
|
1. First ordered item with a really long description that should definitely wrap to the next line when displayed in the editor, testing the hanging indent behavior for numbered lists
|
|
2. Second ordered item — shorter
|
|
1. Nested ordered item that also has quite a long description to verify that the indentation works correctly for nested numbered lists too
|
|
`,
|
|
'/Users/luca/Laputa/procedure/run-sponsorships.md': `---
|
|
title: Run Sponsorships
|
|
is_a: Procedure
|
|
status: Active
|
|
owner: Matteo Cellini
|
|
cadence: Weekly
|
|
belongs_to:
|
|
- "[[responsibility/manage-sponsorships]]"
|
|
---
|
|
|
|
# Run Sponsorships
|
|
|
|
## Weekly Tasks
|
|
- Review pipeline in CRM
|
|
- Follow up with pending proposals
|
|
- Schedule confirmed sponsors
|
|
- Send performance reports to completed sponsors
|
|
|
|
## Templates
|
|
- Proposal template: \`/templates/sponsorship-proposal.md\`
|
|
- Report template: \`/templates/sponsorship-report.md\`
|
|
`,
|
|
'/Users/luca/Laputa/experiment/stock-screener.md': `---
|
|
title: Stock Screener — EMA200 Wick Bounce
|
|
is_a: Experiment
|
|
status: Active
|
|
owner: Luca Rossi
|
|
domains: [Finance, Quantitative Analysis]
|
|
tools: [Python, pandas, TradingView]
|
|
related_to:
|
|
- "[[topic/trading]]"
|
|
- "[[topic/algorithmic-trading]]"
|
|
---
|
|
|
|
# Stock Screener — EMA200 Wick Bounce
|
|
|
|
## Hypothesis
|
|
Stocks that wick below the 200-day EMA and close above it show a **statistically significant bounce** in the following 5-10 days.
|
|
|
|
## Setup
|
|
- Scan for daily candles where:
|
|
- Low < EMA200
|
|
- Close > EMA200
|
|
- Volume > 1.5x average
|
|
- Filter for mid-cap stocks ($2B-$20B)
|
|
|
|
## Results So Far
|
|
| Date | Ticker | Entry | Exit | Return |
|
|
|------|--------|-------|------|--------|
|
|
| 2026-01-15 | AAPL | 182.30 | 189.50 | +3.9% |
|
|
| 2026-01-22 | MSFT | 410.20 | 418.80 | +2.1% |
|
|
|
|
## Next Steps
|
|
- [ ] Backtest on 10 years of data
|
|
- [ ] Add RSI filter for oversold confirmation
|
|
- [ ] Build automated alerts via Python script
|
|
`,
|
|
'/Users/luca/Laputa/note/facebook-ads-strategy.md': `---
|
|
title: Facebook Ads Strategy
|
|
is_a: Note
|
|
belongs_to:
|
|
- "[[project/26q1-laputa-app]]"
|
|
related_to:
|
|
- "[[topic/growth]]"
|
|
- "[[topic/ads]]"
|
|
---
|
|
|
|
# Facebook Ads Strategy
|
|
|
|
## Key Learnings
|
|
- **Lookalike audiences** from newsletter subscribers convert 3x better than interest-based targeting
|
|
- Video ads outperform static images by 40% on engagement
|
|
- Best performing CTA: "Join 50,000 engineers" (social proof)
|
|
|
|
## Budget
|
|
- Monthly budget: $2,000
|
|
- Cost per subscriber: ~$1.50 (down from $3.20 in Q3 2025)
|
|
|
|
## A/B Tests Running
|
|
1. Long-form vs short-form ad copy
|
|
2. Testimonial vs data-driven creative
|
|
`,
|
|
'/Users/luca/Laputa/note/budget-allocation.md': `---
|
|
title: Budget Allocation
|
|
is_a: Note
|
|
belongs_to:
|
|
- "[[project/26q1-laputa-app]]"
|
|
---
|
|
|
|
# Budget Allocation
|
|
|
|
## Q1 2026
|
|
| Category | Budget | Actual | Delta |
|
|
|----------|--------|--------|-------|
|
|
| Ads | $6,000 | $5,400 | -$600 |
|
|
| Tools | $500 | $480 | -$20 |
|
|
| Freelancers | $2,000 | $1,800 | -$200 |
|
|
|
|
## Notes
|
|
- Under budget on ads due to improved targeting efficiency
|
|
- Consider reallocating savings to content production
|
|
`,
|
|
'/Users/luca/Laputa/person/matteo-cellini.md': `---
|
|
title: Matteo Cellini
|
|
is_a: Person
|
|
aliases:
|
|
- Matteo
|
|
---
|
|
|
|
# Matteo Cellini
|
|
|
|
## Role
|
|
Sponsorship manager — handles all sponsor relationships, proposals, and reporting.
|
|
|
|
## Contact
|
|
- Email: matteo@example.com
|
|
- Slack: @matteo
|
|
|
|
## Responsibilities
|
|
- [[Manage Sponsorships]]
|
|
- [[Run Sponsorships]]
|
|
`,
|
|
'/Users/luca/Laputa/event/2026-02-14-laputa-app-kickoff.md': `---
|
|
title: Laputa App Design Session
|
|
is_a: Event
|
|
related_to:
|
|
- "[[project/26q1-laputa-app]]"
|
|
- "[[person/matteo-cellini]]"
|
|
---
|
|
|
|
# Laputa App Design Session
|
|
|
|
## Date
|
|
2026-02-14
|
|
|
|
## Attendees
|
|
- Luca Rossi
|
|
- [[Matteo Cellini]]
|
|
|
|
## Notes
|
|
- Agreed on four-panel layout inspired by Bear Notes
|
|
- CodeMirror 6 for the editor — live preview is critical
|
|
- MVP by end of Q1: sidebar + note list + editor working
|
|
- Inspector panel can wait for M4
|
|
|
|
## Action Items
|
|
- [ ] Luca: finalize ontology mapping
|
|
- [x] Luca: set up Tauri v2 project scaffold
|
|
- [ ] Matteo: test with real vault data
|
|
`,
|
|
'/Users/luca/Laputa/topic/software-development.md': `---
|
|
title: Software Development
|
|
is_a: Topic
|
|
aliases:
|
|
- Dev
|
|
- Coding
|
|
---
|
|
|
|
# Software Development
|
|
|
|
A broad topic covering everything from frontend to systems programming.
|
|
|
|
## Subtopics of Interest
|
|
- **Frontend**: React, TypeScript, CSS
|
|
- **Desktop**: Tauri, Electron alternatives
|
|
- **AI/ML**: LLMs, agents, code generation
|
|
- **Systems**: Rust, performance optimization
|
|
`,
|
|
'/Users/luca/Laputa/topic/trading.md': `---
|
|
title: Trading
|
|
is_a: Topic
|
|
aliases:
|
|
- Algorithmic Trading
|
|
---
|
|
|
|
# Trading
|
|
|
|
## Focus Areas
|
|
- Technical analysis (EMA, RSI, volume patterns)
|
|
- Algorithmic screening and alerts
|
|
- Risk management and position sizing
|
|
|
|
## Active Experiments
|
|
- [[Stock Screener — EMA200 Wick Bounce]]
|
|
`,
|
|
'/Users/luca/Laputa/essay/on-writing-well.md': `---
|
|
title: On Writing Well
|
|
is_a: Essay
|
|
Belongs to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
---
|
|
|
|
# On Writing Well
|
|
|
|
Good writing is lean and confident. Every sentence should serve a purpose.
|
|
`,
|
|
'/Users/luca/Laputa/essay/engineering-leadership-101.md': `---
|
|
title: Engineering Leadership 101
|
|
is_a: Essay
|
|
Belongs to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
Related to:
|
|
- "[[topic/software-development]]"
|
|
---
|
|
|
|
# Engineering Leadership 101
|
|
|
|
The transition from IC to manager is the hardest career shift in engineering.
|
|
`,
|
|
'/Users/luca/Laputa/essay/ai-agents-primer.md': `---
|
|
title: AI Agents Primer
|
|
is_a: Essay
|
|
Belongs to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
---
|
|
|
|
# AI Agents Primer
|
|
|
|
AI agents are autonomous systems that can plan, execute, and adapt to achieve goals.
|
|
`,
|
|
// --- Type documents ---
|
|
'/Users/luca/Laputa/type/project.md': `---
|
|
Is A: Type
|
|
order: 0
|
|
---
|
|
|
|
# Project
|
|
|
|
A **time-bound initiative** that advances a [[type/responsibility|Responsibility]]. Projects have a clear start, end, and deliverables.
|
|
|
|
## Properties
|
|
- **Status**: Active, Paused, Done, Dropped
|
|
- **Owner**: The person accountable
|
|
- **Belongs to**: Usually a Quarter or Responsibility
|
|
`,
|
|
'/Users/luca/Laputa/type/responsibility.md': `---
|
|
Is A: Type
|
|
order: 1
|
|
---
|
|
|
|
# Responsibility
|
|
|
|
An **ongoing area of ownership** — something you're accountable for indefinitely. Responsibilities don't end; they have procedures, projects, and measures attached.
|
|
|
|
## Properties
|
|
- **Status**: Active, Paused, Archived
|
|
- **Owner**: The person accountable
|
|
`,
|
|
'/Users/luca/Laputa/type/procedure.md': `---
|
|
Is A: Type
|
|
order: 2
|
|
---
|
|
|
|
# Procedure
|
|
|
|
A **recurring process** tied to a [[type/responsibility|Responsibility]]. Procedures have a cadence (weekly, monthly) and describe how to do something.
|
|
|
|
## Properties
|
|
- **Status**: Active, Paused
|
|
- **Owner**: The person responsible
|
|
- **Cadence**: Weekly, Monthly, Quarterly
|
|
- **Belongs to**: A Responsibility
|
|
`,
|
|
'/Users/luca/Laputa/type/experiment.md': `---
|
|
Is A: Type
|
|
order: 3
|
|
---
|
|
|
|
# Experiment
|
|
|
|
A **hypothesis-driven investigation** with a clear test and measurable outcome. Experiments are time-bound and have explicit success criteria.
|
|
|
|
## Properties
|
|
- **Status**: Active, Done, Dropped
|
|
- **Owner**: The person running the experiment
|
|
`,
|
|
'/Users/luca/Laputa/type/person.md': `---
|
|
Is A: Type
|
|
order: 4
|
|
---
|
|
|
|
# Person
|
|
|
|
A **person** you interact with — team members, collaborators, contacts. People can own projects, responsibilities, and procedures.
|
|
|
|
## Properties
|
|
- **Aliases**: Alternative names for wikilink resolution
|
|
`,
|
|
'/Users/luca/Laputa/type/event.md': `---
|
|
Is A: Type
|
|
order: 5
|
|
---
|
|
|
|
# Event
|
|
|
|
A **point-in-time occurrence** — meetings, launches, milestones. Events are linked to the entities they relate to.
|
|
|
|
## Properties
|
|
- **Related to**: Entities this event is about
|
|
`,
|
|
'/Users/luca/Laputa/type/topic.md': `---
|
|
Is A: Type
|
|
order: 6
|
|
---
|
|
|
|
# Topic
|
|
|
|
A **subject area** for categorization. Topics group related notes, projects, and resources by theme.
|
|
|
|
## Properties
|
|
- **Aliases**: Alternative names
|
|
`,
|
|
'/Users/luca/Laputa/type/essay.md': `---
|
|
Is A: Type
|
|
order: 7
|
|
---
|
|
|
|
# Essay
|
|
|
|
A **published piece of writing** — newsletter essays, blog posts, articles. Essays belong to a responsibility and may relate to topics.
|
|
|
|
## Properties
|
|
- **Belongs to**: Usually a Responsibility
|
|
`,
|
|
'/Users/luca/Laputa/type/note.md': `---
|
|
Is A: Type
|
|
order: 8
|
|
---
|
|
|
|
# Note
|
|
|
|
A **general-purpose document** — research notes, meeting notes, strategy docs. Notes belong to projects or responsibilities.
|
|
|
|
## Properties
|
|
- **Belongs to**: A Project, Responsibility, or other parent
|
|
`,
|
|
// --- Custom type documents (user-created types) ---
|
|
'/Users/luca/Laputa/type/recipe.md': `---
|
|
Is A: Type
|
|
icon: cooking-pot
|
|
color: orange
|
|
---
|
|
|
|
# Recipe
|
|
|
|
A **recipe** for cooking or baking. Recipes have ingredients, steps, and serving info.
|
|
|
|
## Default Properties
|
|
- **Servings**: Number of servings
|
|
- **Prep Time**: Time to prepare
|
|
- **Cook Time**: Time to cook
|
|
`,
|
|
'/Users/luca/Laputa/type/book.md': `---
|
|
Is A: Type
|
|
icon: book-open
|
|
color: green
|
|
---
|
|
|
|
# Book
|
|
|
|
A **book** you're reading or have read. Track reading progress, notes, and key takeaways.
|
|
|
|
## Default Properties
|
|
- **Author**: The book's author
|
|
- **Status**: Reading, Finished, Abandoned
|
|
- **Rating**: 1-5 stars
|
|
`,
|
|
// --- Trashed entries ---
|
|
'/Users/luca/Laputa/note/old-draft-notes.md': `---
|
|
title: Old Draft Notes
|
|
is_a: Note
|
|
trashed: true
|
|
trashed_at: ${new Date(Date.now() - 86400000 * 5).toISOString().slice(0, 10)}
|
|
belongs_to:
|
|
- "[[project/26q1-laputa-app]]"
|
|
---
|
|
|
|
# Old Draft Notes
|
|
|
|
Some rough draft content that is no longer relevant. Moving to trash.
|
|
`,
|
|
'/Users/luca/Laputa/note/deprecated-api-notes.md': `---
|
|
title: Deprecated API Notes
|
|
is_a: Note
|
|
trashed: true
|
|
trashed_at: ${new Date(Date.now() - 86400000 * 35).toISOString().slice(0, 10)}
|
|
---
|
|
|
|
# Deprecated API Notes
|
|
|
|
Old API documentation for the v1 endpoint. Replaced by v2 docs.
|
|
`,
|
|
'/Users/luca/Laputa/experiment/failed-seo-experiment.md': `---
|
|
title: Failed SEO Experiment
|
|
is_a: Experiment
|
|
status: Dropped
|
|
trashed: true
|
|
trashed_at: ${new Date(Date.now() - 86400000 * 10).toISOString().slice(0, 10)}
|
|
related_to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
---
|
|
|
|
# Failed SEO Experiment
|
|
|
|
Tried programmatic SEO pages. Results were negligible — trashing this.
|
|
`,
|
|
// --- Archived entries ---
|
|
'/Users/luca/Laputa/project/25q3-website-redesign.md': `---
|
|
title: Website Redesign
|
|
is_a: Project
|
|
status: Done
|
|
archived: true
|
|
owner: Luca Rossi
|
|
belongs_to:
|
|
- "[[quarter/q3-2025]]"
|
|
---
|
|
|
|
# Website Redesign
|
|
|
|
Completed redesign of the company website. Migrated from WordPress to Next.js with improved performance and SEO.
|
|
|
|
## Results
|
|
- Page load time: 4.2s → 1.1s
|
|
- Organic traffic: +35% in 3 months
|
|
- Bounce rate: 58% → 42%
|
|
`,
|
|
'/Users/luca/Laputa/experiment/twitter-thread-experiment.md': `---
|
|
title: Twitter Thread Growth Experiment
|
|
is_a: Experiment
|
|
status: Done
|
|
archived: true
|
|
owner: Luca Rossi
|
|
related_to:
|
|
- "[[responsibility/grow-newsletter]]"
|
|
---
|
|
|
|
# Twitter Thread Growth Experiment
|
|
|
|
## Hypothesis
|
|
Publishing 3 Twitter threads per week (instead of 1) will increase newsletter signups by 50%.
|
|
|
|
## Result
|
|
After 6 weeks, signups increased by only 12%. The additional threads had diminishing returns — quality matters more than quantity.
|
|
|
|
## Decision
|
|
Reverted to 1 high-quality thread per week. Archived this experiment.
|
|
`,
|
|
// --- Instances of custom types ---
|
|
'/Users/luca/Laputa/recipe/pasta-carbonara.md': `---
|
|
title: Pasta Carbonara
|
|
is_a: Recipe
|
|
servings: 4
|
|
prep_time: 10 min
|
|
cook_time: 20 min
|
|
---
|
|
|
|
# Pasta Carbonara
|
|
|
|
Classic Roman pasta dish with eggs, pecorino, guanciale, and black pepper.
|
|
|
|
## Ingredients
|
|
- 400g spaghetti
|
|
- 200g guanciale
|
|
- 4 egg yolks + 2 whole eggs
|
|
- 100g Pecorino Romano
|
|
- Black pepper
|
|
`,
|
|
'/Users/luca/Laputa/book/designing-data-intensive-applications.md': `---
|
|
title: Designing Data-Intensive Applications
|
|
is_a: Book
|
|
author: Martin Kleppmann
|
|
status: Finished
|
|
rating: 5
|
|
---
|
|
|
|
# Designing Data-Intensive Applications
|
|
|
|
Essential reading for anyone building distributed systems. Covers replication, partitioning, transactions, and stream processing.
|
|
`,
|
|
}
|
|
|
|
const MOCK_ENTRIES: VaultEntry[] = [
|
|
{
|
|
path: '/Users/luca/Laputa/project/26q1-laputa-app.md',
|
|
filename: '26q1-laputa-app.md',
|
|
title: 'Build Laputa App',
|
|
isA: 'Project',
|
|
aliases: ['Laputa App'],
|
|
belongsTo: ['[[quarter/q1-2026]]'],
|
|
relatedTo: ['[[topic/software-development]]'],
|
|
status: 'Active',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000,
|
|
createdAt: Date.now() / 1000 - 86400 * 60,
|
|
fileSize: 2048,
|
|
snippet: 'This paragraph has bold text, italic text, bold italic, strikethrough, and inline code. Here\'s a regular link and a wiki-link to Matteo Cellini.',
|
|
relationships: {
|
|
'Belongs to': ['[[quarter/q1-2026]]'],
|
|
'Related to': ['[[topic/software-development]]'],
|
|
'Type': ['[[type/project]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/responsibility/grow-newsletter.md',
|
|
filename: 'grow-newsletter.md',
|
|
title: 'Grow Newsletter',
|
|
isA: 'Responsibility',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: ['[[topic/growth]]'],
|
|
status: 'Active',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 3600,
|
|
createdAt: Date.now() / 1000 - 86400 * 180,
|
|
fileSize: 1024,
|
|
snippet: 'Build a sustainable audience through high-quality weekly essays on engineering leadership, AI, and personal systems.',
|
|
relationships: {
|
|
'Has': [
|
|
'[[essay/on-writing-well|On Writing Well]]',
|
|
'[[essay/engineering-leadership-101|Engineering Leadership 101]]',
|
|
'[[essay/ai-agents-primer|AI Agents Primer]]',
|
|
],
|
|
'Topics': ['[[topic/growth]]', '[[topic/writing]]'],
|
|
'Related to': ['[[topic/growth]]'],
|
|
'Type': ['[[type/responsibility]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/responsibility/manage-sponsorships.md',
|
|
filename: 'manage-sponsorships.md',
|
|
title: 'Manage Sponsorships',
|
|
isA: 'Responsibility',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: 'Active',
|
|
owner: 'Matteo Cellini',
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 7200,
|
|
createdAt: Date.now() / 1000 - 86400 * 150,
|
|
fileSize: 890,
|
|
snippet: 'Revenue stream from newsletter sponsorships. Matteo Cellini handles day-to-day operations.',
|
|
relationships: {
|
|
'Owner': ['[[person/matteo-cellini|Matteo Cellini]]'],
|
|
'Type': ['[[type/responsibility]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/procedure/write-weekly-essays.md',
|
|
filename: 'write-weekly-essays.md',
|
|
title: 'Write Weekly Essays',
|
|
isA: 'Procedure',
|
|
aliases: [],
|
|
belongsTo: ['[[responsibility/grow-newsletter]]'],
|
|
relatedTo: [],
|
|
status: 'Paused',
|
|
owner: 'Luca Rossi',
|
|
cadence: 'Weekly',
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400,
|
|
createdAt: Date.now() / 1000 - 86400 * 120,
|
|
fileSize: 512,
|
|
snippet: 'Monday: Pick topic, outline Tuesday: First draft Wednesday: Edit and polish Thursday: Schedule for Tuesday send',
|
|
relationships: {
|
|
'Belongs to': ['[[responsibility/grow-newsletter]]'],
|
|
'Type': ['[[type/procedure]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/procedure/run-sponsorships.md',
|
|
filename: 'run-sponsorships.md',
|
|
title: 'Run Sponsorships',
|
|
isA: 'Procedure',
|
|
aliases: [],
|
|
belongsTo: ['[[responsibility/manage-sponsorships]]'],
|
|
relatedTo: [],
|
|
status: 'Done',
|
|
owner: 'Matteo Cellini',
|
|
cadence: 'Weekly',
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 2,
|
|
createdAt: Date.now() / 1000 - 86400 * 100,
|
|
fileSize: 640,
|
|
snippet: 'Review pipeline in CRM Follow up with pending proposals Schedule confirmed sponsors Send performance reports to completed sponsors',
|
|
relationships: {
|
|
'Belongs to': ['[[responsibility/manage-sponsorships]]'],
|
|
'Type': ['[[type/procedure]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/experiment/stock-screener.md',
|
|
filename: 'stock-screener.md',
|
|
title: 'Stock Screener — EMA200 Wick Bounce',
|
|
isA: 'Experiment',
|
|
aliases: ['Trading Screener'],
|
|
belongsTo: [],
|
|
relatedTo: ['[[topic/trading]]', '[[topic/algorithmic-trading]]'],
|
|
status: 'Paused',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400,
|
|
createdAt: Date.now() / 1000 - 86400 * 45,
|
|
fileSize: 3200,
|
|
snippet: 'Stocks that wick below the 200-day EMA and close above it show a statistically significant bounce in the following 5-10 days.',
|
|
relationships: {
|
|
'Related to': ['[[topic/trading]]', '[[topic/algorithmic-trading]]'],
|
|
'Has Data': ['[[data/ema200-backtest-results]]'],
|
|
'Type': ['[[type/experiment]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/note/facebook-ads-strategy.md',
|
|
filename: 'facebook-ads-strategy.md',
|
|
title: 'Facebook Ads Strategy',
|
|
isA: 'Note',
|
|
aliases: [],
|
|
belongsTo: ['[[project/26q1-laputa-app]]'],
|
|
relatedTo: ['[[topic/growth]]', '[[topic/ads]]'],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 3600 * 5,
|
|
createdAt: Date.now() / 1000 - 86400 * 30,
|
|
fileSize: 847,
|
|
snippet: 'Lookalike audiences from newsletter subscribers convert 3x better than interest-based targeting Video ads outperform static images by 40% on engagement',
|
|
relationships: {
|
|
'Belongs to': ['[[project/26q1-laputa-app]]'],
|
|
'Related to': ['[[topic/growth]]', '[[topic/ads]]'],
|
|
'Type': ['[[type/note]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/note/budget-allocation.md',
|
|
filename: 'budget-allocation.md',
|
|
title: 'Budget Allocation',
|
|
isA: 'Note',
|
|
aliases: [],
|
|
belongsTo: ['[[project/26q1-laputa-app]]'],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400,
|
|
createdAt: Date.now() / 1000 - 86400 * 20,
|
|
fileSize: 560,
|
|
snippet: 'Under budget on ads due to improved targeting efficiency Consider reallocating savings to content production',
|
|
relationships: {
|
|
'Belongs to': ['[[project/26q1-laputa-app]]'],
|
|
'Type': ['[[type/note]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/person/matteo-cellini.md',
|
|
filename: 'matteo-cellini.md',
|
|
title: 'Matteo Cellini',
|
|
isA: 'Person',
|
|
aliases: ['Matteo'],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 7,
|
|
createdAt: Date.now() / 1000 - 86400 * 200,
|
|
fileSize: 320,
|
|
snippet: 'Sponsorship manager — handles all sponsor relationships, proposals, and reporting.',
|
|
relationships: {
|
|
'Type': ['[[type/person]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/event/2026-02-14-laputa-app-kickoff.md',
|
|
filename: '2026-02-14-laputa-app-kickoff.md',
|
|
title: 'Laputa App Design Session',
|
|
isA: 'Event',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: ['[[project/26q1-laputa-app]]', '[[person/matteo-cellini]]'],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 3600 * 2,
|
|
createdAt: Date.now() / 1000 - 86400 * 7,
|
|
fileSize: 1200,
|
|
snippet: 'Agreed on four-panel layout inspired by Bear Notes CodeMirror 6 for the editor — live preview is critical MVP by end of Q1.',
|
|
relationships: {
|
|
'Related to': ['[[project/26q1-laputa-app]]', '[[person/matteo-cellini]]'],
|
|
'Type': ['[[type/event]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/topic/software-development.md',
|
|
filename: 'software-development.md',
|
|
title: 'Software Development',
|
|
isA: 'Topic',
|
|
aliases: ['Dev', 'Coding'],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 256,
|
|
snippet: 'A broad topic covering everything from frontend to systems programming.',
|
|
relationships: {
|
|
'Notes': ['[[note/facebook-ads-strategy]]', '[[note/budget-allocation]]'],
|
|
'Type': ['[[type/topic]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/topic/trading.md',
|
|
filename: 'trading.md',
|
|
title: 'Trading',
|
|
isA: 'Topic',
|
|
aliases: ['Algorithmic Trading'],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 14,
|
|
createdAt: Date.now() / 1000 - 86400 * 300,
|
|
fileSize: 180,
|
|
snippet: 'Technical analysis (EMA, RSI, volume patterns) Algorithmic screening and alerts Risk management and position sizing',
|
|
relationships: {
|
|
'Notes': ['[[experiment/stock-screener]]'],
|
|
'Type': ['[[type/topic]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/essay/on-writing-well.md',
|
|
filename: 'on-writing-well.md',
|
|
title: 'On Writing Well',
|
|
isA: 'Essay',
|
|
aliases: [],
|
|
belongsTo: ['[[responsibility/grow-newsletter]]'],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 3,
|
|
createdAt: Date.now() / 1000 - 86400 * 14,
|
|
fileSize: 4200,
|
|
snippet: 'Good writing is lean and confident. Every sentence should serve a purpose.',
|
|
relationships: {
|
|
'Belongs to': ['[[responsibility/grow-newsletter]]'],
|
|
'Type': ['[[type/essay]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/essay/engineering-leadership-101.md',
|
|
filename: 'engineering-leadership-101.md',
|
|
title: 'Engineering Leadership 101',
|
|
isA: 'Essay',
|
|
aliases: [],
|
|
belongsTo: ['[[responsibility/grow-newsletter]]'],
|
|
relatedTo: ['[[topic/software-development]]'],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 7,
|
|
createdAt: Date.now() / 1000 - 86400 * 30,
|
|
fileSize: 3800,
|
|
snippet: 'The transition from IC to manager is the hardest career shift in engineering.',
|
|
relationships: {
|
|
'Belongs to': ['[[responsibility/grow-newsletter]]'],
|
|
'Related to': ['[[topic/software-development]]'],
|
|
'Type': ['[[type/essay]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/essay/ai-agents-primer.md',
|
|
filename: 'ai-agents-primer.md',
|
|
title: 'AI Agents Primer',
|
|
isA: 'Essay',
|
|
aliases: [],
|
|
belongsTo: ['[[responsibility/grow-newsletter]]'],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 10,
|
|
createdAt: Date.now() / 1000 - 86400 * 21,
|
|
fileSize: 5100,
|
|
snippet: 'AI agents are autonomous systems that can plan, execute, and adapt to achieve goals.',
|
|
relationships: {
|
|
'Belongs to': ['[[responsibility/grow-newsletter]]'],
|
|
'Type': ['[[type/essay]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
// --- Type documents ---
|
|
{
|
|
path: '/Users/luca/Laputa/type/project.md',
|
|
filename: 'project.md',
|
|
title: 'Project',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 320,
|
|
snippet: 'A time-bound initiative that advances a Responsibility. Projects have a clear start, end, and deliverables.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 0,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/responsibility.md',
|
|
filename: 'responsibility.md',
|
|
title: 'Responsibility',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 280,
|
|
snippet: 'An ongoing area of ownership — something you\'re accountable for indefinitely.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 1,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/procedure.md',
|
|
filename: 'procedure.md',
|
|
title: 'Procedure',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 310,
|
|
snippet: 'A recurring process tied to a Responsibility. Procedures have a cadence and describe how to do something.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 2,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/experiment.md',
|
|
filename: 'experiment.md',
|
|
title: 'Experiment',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 290,
|
|
snippet: 'A hypothesis-driven investigation with a clear test and measurable outcome.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 3,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/person.md',
|
|
filename: 'person.md',
|
|
title: 'Person',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 200,
|
|
snippet: 'A person you interact with — team members, collaborators, contacts.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 4,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/event.md',
|
|
filename: 'event.md',
|
|
title: 'Event',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 180,
|
|
snippet: 'A point-in-time occurrence — meetings, launches, milestones.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 5,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/topic.md',
|
|
filename: 'topic.md',
|
|
title: 'Topic',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 170,
|
|
snippet: 'A subject area for categorization. Topics group related notes, projects, and resources by theme.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 6,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/essay.md',
|
|
filename: 'essay.md',
|
|
title: 'Essay',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 200,
|
|
snippet: 'A published piece of writing — newsletter essays, blog posts, articles.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 7,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/note.md',
|
|
filename: 'note.md',
|
|
title: 'Note',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 190,
|
|
snippet: 'A general-purpose document — research notes, meeting notes, strategy docs.',
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: 8,
|
|
},
|
|
// --- Custom type documents (user-created types) ---
|
|
{
|
|
path: '/Users/luca/Laputa/type/recipe.md',
|
|
filename: 'recipe.md',
|
|
title: 'Recipe',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 250,
|
|
snippet: 'A recipe for cooking or baking. Recipes have ingredients, steps, and serving info.',
|
|
relationships: {},
|
|
icon: 'cooking-pot',
|
|
color: 'orange',
|
|
order: 9,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/type/book.md',
|
|
filename: 'book.md',
|
|
title: 'Book',
|
|
isA: 'Type',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
|
createdAt: Date.now() / 1000 - 86400 * 365,
|
|
fileSize: 220,
|
|
snippet: 'A book you\'re reading or have read. Track reading progress, notes, and key takeaways.',
|
|
relationships: {},
|
|
icon: 'book-open',
|
|
color: 'green',
|
|
order: 10,
|
|
},
|
|
// --- Instances of custom types ---
|
|
{
|
|
path: '/Users/luca/Laputa/recipe/pasta-carbonara.md',
|
|
filename: 'pasta-carbonara.md',
|
|
title: 'Pasta Carbonara',
|
|
isA: 'Recipe',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 5,
|
|
createdAt: Date.now() / 1000 - 86400 * 10,
|
|
fileSize: 420,
|
|
snippet: 'Classic Roman pasta dish with eggs, pecorino, guanciale, and black pepper.',
|
|
relationships: {
|
|
'Type': ['[[type/recipe]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/book/designing-data-intensive-applications.md',
|
|
filename: 'designing-data-intensive-applications.md',
|
|
title: 'Designing Data-Intensive Applications',
|
|
isA: 'Book',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 14,
|
|
createdAt: Date.now() / 1000 - 86400 * 60,
|
|
fileSize: 380,
|
|
snippet: 'Essential reading for anyone building distributed systems. Covers replication, partitioning, transactions.',
|
|
relationships: {
|
|
'Type': ['[[type/book]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
// --- Trashed entries ---
|
|
{
|
|
path: '/Users/luca/Laputa/note/old-draft-notes.md',
|
|
filename: 'old-draft-notes.md',
|
|
title: 'Old Draft Notes',
|
|
isA: 'Note',
|
|
aliases: [],
|
|
belongsTo: ['[[project/26q1-laputa-app]]'],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: true,
|
|
trashedAt: Date.now() / 1000 - 86400 * 5,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 10,
|
|
createdAt: null,
|
|
fileSize: 280,
|
|
snippet: 'Some rough draft content that is no longer relevant. Moving to trash.',
|
|
relationships: {
|
|
'Belongs to': ['[[project/26q1-laputa-app]]'],
|
|
'Type': ['[[type/note]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/note/deprecated-api-notes.md',
|
|
filename: 'deprecated-api-notes.md',
|
|
title: 'Deprecated API Notes',
|
|
isA: 'Note',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
owner: null,
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: true,
|
|
trashedAt: Date.now() / 1000 - 86400 * 35,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 40,
|
|
createdAt: null,
|
|
fileSize: 190,
|
|
snippet: 'Old API documentation for the v1 endpoint. Replaced by v2 docs.',
|
|
relationships: {
|
|
'Type': ['[[type/note]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/experiment/failed-seo-experiment.md',
|
|
filename: 'failed-seo-experiment.md',
|
|
title: 'Failed SEO Experiment',
|
|
isA: 'Experiment',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: ['[[responsibility/grow-newsletter]]'],
|
|
status: 'Dropped',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: false,
|
|
trashed: true,
|
|
trashedAt: Date.now() / 1000 - 86400 * 10,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 15,
|
|
createdAt: null,
|
|
fileSize: 340,
|
|
snippet: 'Tried programmatic SEO pages. Results were negligible — trashing this.',
|
|
relationships: {
|
|
'Related to': ['[[responsibility/grow-newsletter]]'],
|
|
'Type': ['[[type/experiment]]'],
|
|
},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
},
|
|
// --- Archived entries ---
|
|
{
|
|
path: '/Users/luca/Laputa/project/25q3-website-redesign.md',
|
|
filename: '25q3-website-redesign.md',
|
|
title: 'Website Redesign',
|
|
isA: 'Project',
|
|
aliases: [],
|
|
belongsTo: ['[[quarter/q3-2025]]'],
|
|
relatedTo: [],
|
|
status: 'Done',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: true,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 120,
|
|
createdAt: Date.now() / 1000 - 86400 * 200,
|
|
fileSize: 680,
|
|
snippet: 'Completed redesign of the company website. Migrated from WordPress to Next.js with improved performance and SEO.',
|
|
relationships: {
|
|
'Belongs to': ['[[quarter/q3-2025]]'],
|
|
'Type': ['[[type/project]]'],
|
|
},
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/experiment/twitter-thread-experiment.md',
|
|
filename: 'twitter-thread-experiment.md',
|
|
title: 'Twitter Thread Growth Experiment',
|
|
isA: 'Experiment',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: ['[[responsibility/grow-newsletter]]'],
|
|
status: 'Done',
|
|
owner: 'Luca Rossi',
|
|
cadence: null,
|
|
archived: true,
|
|
trashed: false,
|
|
trashedAt: null,
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
|
createdAt: Date.now() / 1000 - 86400 * 150,
|
|
fileSize: 520,
|
|
snippet: 'Publishing 3 Twitter threads per week instead of 1 will increase newsletter signups by 50%. Result: only 12% increase.',
|
|
relationships: {
|
|
'Related to': ['[[responsibility/grow-newsletter]]'],
|
|
'Type': ['[[type/experiment]]'],
|
|
},
|
|
},
|
|
]
|
|
|
|
function mockFileHistory(path: string): GitCommit[] {
|
|
const filename = path.split('/').pop()?.replace('.md', '') ?? 'unknown'
|
|
const now = Math.floor(Date.now() / 1000)
|
|
return [
|
|
{
|
|
hash: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0',
|
|
shortHash: 'a1b2c3d',
|
|
message: `Update ${filename} with latest changes`,
|
|
author: 'Luca Rossi',
|
|
date: now - 86400 * 2,
|
|
},
|
|
{
|
|
hash: 'e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0v1w2x3',
|
|
shortHash: 'e4f5g6h',
|
|
message: `Add new section to ${filename}`,
|
|
author: 'Luca Rossi',
|
|
date: now - 86400 * 5,
|
|
},
|
|
{
|
|
hash: 'i7j8k9l0m1n2o3p4q5r6s7t8u9v0w1x2y3z4a5b6',
|
|
shortHash: 'i7j8k9l',
|
|
message: `Fix formatting in ${filename}`,
|
|
author: 'Luca Rossi',
|
|
date: now - 86400 * 12,
|
|
},
|
|
{
|
|
hash: 'm0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d7e8f9',
|
|
shortHash: 'm0n1o2p',
|
|
message: `Create ${filename}`,
|
|
author: 'Luca Rossi',
|
|
date: now - 86400 * 30,
|
|
},
|
|
]
|
|
}
|
|
|
|
function mockModifiedFiles(): ModifiedFile[] {
|
|
return [
|
|
{
|
|
path: '/Users/luca/Laputa/project/26q1-laputa-app.md',
|
|
relativePath: 'project/26q1-laputa-app.md',
|
|
status: 'modified',
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/note/facebook-ads-strategy.md',
|
|
relativePath: 'note/facebook-ads-strategy.md',
|
|
status: 'modified',
|
|
},
|
|
{
|
|
path: '/Users/luca/Laputa/note/new-draft.md',
|
|
relativePath: 'note/new-draft.md',
|
|
status: 'untracked',
|
|
},
|
|
]
|
|
}
|
|
|
|
function mockFileDiff(path: string): string {
|
|
const filename = path.split('/').pop() ?? 'unknown'
|
|
return `diff --git a/${filename} b/${filename}
|
|
index abc1234..def5678 100644
|
|
--- a/${filename}
|
|
+++ b/${filename}
|
|
@@ -1,8 +1,10 @@
|
|
---
|
|
title: Example Note
|
|
is_a: Note
|
|
+status: Active
|
|
---
|
|
|
|
# Example Note
|
|
|
|
-This is the original content.
|
|
+This is the updated content.
|
|
+
|
|
+A new paragraph has been added.`
|
|
}
|
|
|
|
function mockFileDiffAtCommit(path: string, commitHash: string): string {
|
|
const filename = path.split('/').pop() ?? 'unknown'
|
|
const shortHash = commitHash.slice(0, 7)
|
|
return `diff --git a/${filename} b/${filename}
|
|
index abc1234..${shortHash} 100644
|
|
--- a/${filename}
|
|
+++ b/${filename}
|
|
@@ -5,3 +5,5 @@
|
|
---
|
|
|
|
# Example Note
|
|
-Old paragraph from before ${shortHash}.
|
|
+Updated paragraph at commit ${shortHash}.
|
|
+
|
|
+New content added in this commit.`
|
|
}
|
|
|
|
let mockHasChanges = true
|
|
|
|
let mockSettings: Settings = {
|
|
anthropic_key: null,
|
|
openai_key: null,
|
|
google_key: null,
|
|
github_token: 'gho_mock_token_for_testing',
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- mock handler map accepts heterogeneous arg types
|
|
const mockHandlers: Record<string, (args: any) => any> = {
|
|
list_vault: () => MOCK_ENTRIES,
|
|
get_note_content: (args: { path: string }) => MOCK_CONTENT[args.path] ?? '',
|
|
get_all_content: () => MOCK_CONTENT,
|
|
get_file_history: (args: { path: string }) => mockFileHistory(args.path),
|
|
get_modified_files: () => mockHasChanges ? mockModifiedFiles() : [],
|
|
get_file_diff: (args: { path: string }) => mockFileDiff(args.path),
|
|
get_file_diff_at_commit: (args: { path: string; commitHash: string }) => mockFileDiffAtCommit(args.path, args.commitHash),
|
|
git_commit: (args: { message: string }) => {
|
|
mockHasChanges = false
|
|
return `[main abc1234] ${args.message}\n 3 files changed`
|
|
},
|
|
git_push: () => {
|
|
return 'Everything up-to-date'
|
|
},
|
|
ai_chat: (args: { request: { messages: { role: string; content: string }[]; model?: string; system?: string } }) => {
|
|
const lastMsg = args.request.messages[args.request.messages.length - 1]?.content ?? ''
|
|
const lower = lastMsg.toLowerCase()
|
|
let content = `I can help you with that. Could you provide more details about what you'd like to know?`
|
|
if (lower.includes('summarize')) {
|
|
content = `Here's a summary of the note:\n\n**Key Points:**\n- The note covers the main topic and its related concepts\n- It includes actionable items and references to other notes\n- Several wiki-links connect it to the broader knowledge base\n\nWould you like me to expand on any of these points?`
|
|
} else if (lower.includes('expand')) {
|
|
content = `Here are suggestions to expand this note:\n\n1. **Add context** — Include background information\n2. **Link related notes** — Connect to [[related topics]]\n3. **Add examples** — Include concrete examples\n4. **Update status** — Reflect current progress`
|
|
} else if (lower.includes('grammar')) {
|
|
content = `Grammar review complete. The writing is clear and well-structured. Minor suggestions:\n\n- Consider varying sentence lengths for better rhythm\n- A few passive constructions could be made active`
|
|
}
|
|
return {
|
|
content,
|
|
model: args.request.model ?? 'claude-3-5-haiku-20241022',
|
|
stop_reason: 'end_turn',
|
|
}
|
|
},
|
|
save_image: (args: { vault_path?: string; filename: string; data: string }) => {
|
|
// Return a plausible file path matching the real Rust backend behavior
|
|
const vault = args.vault_path ?? '/Users/luca/Laputa'
|
|
const timestamp = Date.now()
|
|
return `${vault}/attachments/${timestamp}-${args.filename}`
|
|
},
|
|
get_settings: () => ({ ...mockSettings }),
|
|
save_settings: (args: { settings: Settings }) => {
|
|
const s = args.settings
|
|
mockSettings = {
|
|
anthropic_key: s.anthropic_key?.trim() || null,
|
|
openai_key: s.openai_key?.trim() || null,
|
|
google_key: s.google_key?.trim() || null,
|
|
github_token: s.github_token?.trim() || null,
|
|
}
|
|
return null
|
|
},
|
|
rename_note: (args: { vault_path: string; old_path: string; new_title: string }) => {
|
|
const oldContent = MOCK_CONTENT[args.old_path] ?? ''
|
|
const slug = args.new_title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '')
|
|
const parentDir = args.old_path.replace(/\/[^/]+$/, '')
|
|
const newPath = `${parentDir}/${slug}.md`
|
|
|
|
// Update H1 heading in content
|
|
const newContent = oldContent.replace(/^# .+$/m, `# ${args.new_title}`)
|
|
|
|
// Move content to new path
|
|
delete MOCK_CONTENT[args.old_path]
|
|
MOCK_CONTENT[newPath] = newContent
|
|
|
|
// Update wikilinks in other notes
|
|
const oldEntry = MOCK_ENTRIES.find(e => e.path === args.old_path)
|
|
const oldTitle = oldEntry?.title ?? ''
|
|
let updatedFiles = 0
|
|
if (oldTitle) {
|
|
const pattern = new RegExp(`\\[\\[${oldTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\|[^\\]]*?)?\\]\\]`, 'g')
|
|
for (const [path, content] of Object.entries(MOCK_CONTENT)) {
|
|
if (path === newPath) continue
|
|
const replaced = content.replace(pattern, (_m: string, pipe: string | undefined) =>
|
|
pipe ? `[[${args.new_title}${pipe}]]` : `[[${args.new_title}]]`
|
|
)
|
|
if (replaced !== content) {
|
|
MOCK_CONTENT[path] = replaced
|
|
updatedFiles++
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof window !== 'undefined') {
|
|
window.__mockContent = MOCK_CONTENT
|
|
}
|
|
return { new_path: newPath, updated_files: updatedFiles }
|
|
},
|
|
github_list_repos: () => [
|
|
{ name: 'laputa-vault', full_name: 'lucaong/laputa-vault', description: 'Personal knowledge vault — markdown + YAML frontmatter', private: true, clone_url: 'https://github.com/lucaong/laputa-vault.git', html_url: 'https://github.com/lucaong/laputa-vault', updated_at: '2026-02-20T10:30:00Z' },
|
|
{ name: 'laputa-app', full_name: 'lucaong/laputa-app', description: 'Laputa desktop app — Tauri + React + CodeMirror 6', private: false, clone_url: 'https://github.com/lucaong/laputa-app.git', html_url: 'https://github.com/lucaong/laputa-app', updated_at: '2026-02-19T15:00:00Z' },
|
|
{ name: 'dotfiles', full_name: 'lucaong/dotfiles', description: 'My macOS dotfiles and config', private: false, clone_url: 'https://github.com/lucaong/dotfiles.git', html_url: 'https://github.com/lucaong/dotfiles', updated_at: '2026-01-15T08:00:00Z' },
|
|
{ name: 'notes-archive', full_name: 'lucaong/notes-archive', description: 'Archived notes from 2024', private: true, clone_url: 'https://github.com/lucaong/notes-archive.git', html_url: 'https://github.com/lucaong/notes-archive', updated_at: '2025-12-01T12:00:00Z' },
|
|
{ name: 'obsidian-vault', full_name: 'lucaong/obsidian-vault', description: null, private: true, clone_url: 'https://github.com/lucaong/obsidian-vault.git', html_url: 'https://github.com/lucaong/obsidian-vault', updated_at: '2025-11-05T09:00:00Z' },
|
|
],
|
|
github_create_repo: (args: { name: string; private: boolean }) => ({
|
|
name: args.name,
|
|
full_name: `lucaong/${args.name}`,
|
|
description: 'Laputa vault',
|
|
private: args.private,
|
|
clone_url: `https://github.com/lucaong/${args.name}.git`,
|
|
html_url: `https://github.com/lucaong/${args.name}`,
|
|
updated_at: new Date().toISOString(),
|
|
}),
|
|
clone_repo: (args: { url: string; local_path: string }) => `Cloned to ${args.local_path}`,
|
|
}
|
|
|
|
export function isTauri(): boolean {
|
|
return typeof window !== 'undefined' && ('__TAURI__' in window || '__TAURI_INTERNALS__' in window)
|
|
}
|
|
|
|
// Initialize window.__mockContent for browser testing
|
|
if (typeof window !== 'undefined') {
|
|
window.__mockContent = MOCK_CONTENT
|
|
}
|
|
|
|
/** Register content for a new entry in mock mode (for get_note_content calls) */
|
|
export function addMockEntry(_entry: VaultEntry, content: string) {
|
|
MOCK_CONTENT[_entry.path] = content
|
|
if (typeof window !== 'undefined') {
|
|
window.__mockContent = MOCK_CONTENT
|
|
}
|
|
}
|
|
|
|
/** Update content for an existing entry in mock mode */
|
|
export function updateMockContent(path: string, content: string) {
|
|
MOCK_CONTENT[path] = content
|
|
if (typeof window !== 'undefined') {
|
|
window.__mockContent = MOCK_CONTENT
|
|
}
|
|
}
|
|
|
|
export async function mockInvoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
|
|
// Try the vault API first for commands that read vault data
|
|
const apiAvailable = await checkVaultApi()
|
|
if (apiAvailable) {
|
|
try {
|
|
if (cmd === 'list_vault' && args?.path) {
|
|
const res = await fetch(`/api/vault/list?path=${encodeURIComponent(args.path as string)}`)
|
|
if (res.ok) return (await res.json()) as T
|
|
}
|
|
if (cmd === 'get_note_content' && args?.path) {
|
|
const res = await fetch(`/api/vault/content?path=${encodeURIComponent(args.path as string)}`)
|
|
if (res.ok) {
|
|
const { content } = await res.json()
|
|
return content as T
|
|
}
|
|
}
|
|
if (cmd === 'get_all_content' && args?.path) {
|
|
const res = await fetch(`/api/vault/all-content?path=${encodeURIComponent(args.path as string)}`)
|
|
if (res.ok) return (await res.json()) as T
|
|
}
|
|
} catch (err) {
|
|
console.warn(`[mock-tauri] Vault API call failed for ${cmd}, falling back to mock:`, err)
|
|
}
|
|
}
|
|
|
|
// Fall back to hardcoded mock handlers
|
|
const handler = mockHandlers[cmd]
|
|
if (handler) {
|
|
await new Promise((r) => setTimeout(r, 100))
|
|
return handler(args) as T
|
|
}
|
|
throw new Error(`No mock handler for command: ${cmd}`)
|
|
}
|