Claude-code-plugins-plus fireflies-local-dev-loop
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/fireflies-pack/skills/fireflies-local-dev-loop" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-fireflies-local-dev-loop && rm -rf "$T"
manifest:
plugins/saas-packs/fireflies-pack/skills/fireflies-local-dev-loop/SKILL.mdsource content
Fireflies.ai Local Dev Loop
Overview
Set up a fast local development workflow for Fireflies.ai integrations: project structure, mock data for offline development, test helpers, and API response recording for replay.
Prerequisites
- Completed
setupfireflies-install-auth - Node.js 18+ with npm/pnpm
- Vitest for testing
Instructions
Step 1: Project Structure
my-fireflies-app/ src/ lib/ fireflies-client.ts # GraphQL client (see fireflies-sdk-patterns) transcript-service.ts # Business logic layer types/ fireflies.ts # TypeScript interfaces tests/ fixtures/ transcript.json # Recorded API responses fireflies-client.test.ts transcript-service.test.ts .env.local # FIREFLIES_API_KEY (git-ignored) .env.example # Template without secrets
Step 2: Record Real API Responses as Fixtures
// scripts/record-fixtures.ts import { FirefliesClient } from "../src/lib/fireflies-client"; import { writeFileSync, mkdirSync } from "fs"; async function recordFixtures() { const client = new FirefliesClient(); mkdirSync("tests/fixtures", { recursive: true }); // Record user const user = await client.query(`{ user { name email user_id is_admin } }`); writeFileSync("tests/fixtures/user.json", JSON.stringify(user, null, 2)); // Record transcript list const list = await client.query(`{ transcripts(limit: 3) { id title date duration organizer_email summary { overview action_items keywords } } }`); writeFileSync("tests/fixtures/transcripts.json", JSON.stringify(list, null, 2)); // Record single transcript with sentences const id = list.transcripts[0]?.id; if (id) { const full = await client.query(` query($id: String!) { transcript(id: $id) { id title date duration speakers { id name } sentences { speaker_name text start_time end_time } summary { overview action_items keywords } analytics { sentiments { positive_pct negative_pct neutral_pct } speakers { name duration word_count } } } } `, { id }); writeFileSync("tests/fixtures/transcript-full.json", JSON.stringify(full, null, 2)); } console.log("Fixtures recorded in tests/fixtures/"); } recordFixtures().catch(console.error);
Step 3: Mock Client for Tests
// tests/helpers/mock-fireflies.ts import { readFileSync } from "fs"; export function createMockClient() { const fixtures: Record<string, any> = {}; return { loadFixture(name: string) { fixtures[name] = JSON.parse( readFileSync(`tests/fixtures/${name}.json`, "utf-8") ); }, async query(gql: string, variables?: Record<string, any>) { // Match query to fixture by operation if (gql.includes("transcripts(")) return fixtures["transcripts"]; if (gql.includes("transcript(id:")) return fixtures["transcript-full"]; if (gql.includes("user {")) return fixtures["user"]; throw new Error(`No fixture for query: ${gql.slice(0, 50)}`); }, }; }
Step 4: Write Tests
// tests/transcript-service.test.ts import { describe, it, expect, vi, beforeEach } from "vitest"; import { createMockClient } from "./helpers/mock-fireflies"; describe("Transcript Service", () => { let mockClient: ReturnType<typeof createMockClient>; beforeEach(() => { mockClient = createMockClient(); mockClient.loadFixture("transcripts"); mockClient.loadFixture("transcript-full"); }); it("should list recent transcripts", async () => { const data = await mockClient.query("{ transcripts(limit: 3) { id title } }"); expect(data.transcripts).toBeDefined(); expect(data.transcripts.length).toBeGreaterThan(0); }); it("should fetch full transcript with sentences", async () => { const data = await mockClient.query( `query($id: String!) { transcript(id: $id) { sentences { text } } }`, { id: "test-id" } ); expect(data.transcript.sentences).toBeDefined(); }); it("should handle API errors gracefully", async () => { const errorClient = { query: vi.fn().mockRejectedValue(new Error("Fireflies: auth_failed")), }; await expect(errorClient.query("{ user { email } }")) .rejects.toThrow("auth_failed"); }); });
Step 5: Development Scripts
{ "scripts": { "dev": "tsx watch src/index.ts", "test": "vitest", "test:watch": "vitest --watch", "record-fixtures": "tsx scripts/record-fixtures.ts", "typecheck": "tsc --noEmit" } }
Step 6: Environment Setup
set -euo pipefail # Create .env from template cp .env.example .env.local # .env.example echo 'FIREFLIES_API_KEY=your-key-here' > .env.example # .gitignore additions echo '.env.local' >> .gitignore echo 'tests/fixtures/*.json' >> .gitignore
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Fixture not found | Fixtures not recorded | Run |
| Auth error in tests | Using real API key in CI | Use mock client, not real API |
| Type mismatch | API schema changed | Re-record fixtures, update types |
| Rate limit during recording | Too many fixture requests | Record once, commit fixtures |
Output
- Project structure with typed client and service layers
- Recorded API fixtures for offline testing
- Mock client for unit tests
- Dev scripts with hot reload and watch mode
Resources
Next Steps
See
fireflies-sdk-patterns for production-ready client patterns.