Development
Contributing to Daily Vibe - development setup, guidelines, and contribution process
Development
Daily Vibe is an open-source project that welcomes contributions from the community. Whether you're fixing bugs, adding features, or improving documentation, this guide will help you get started.
Getting Started
Prerequisites
Before contributing to Daily Vibe, ensure you have:
- Node.js >= 18.0.0
- pnpm (recommended) or npm
- Git for version control
- A code editor (VS Code recommended)
Development Setup
# Fork the repository on GitHub first, then clone your fork
git clone https://github.com/YOUR_USERNAME/daily-vibe.git
cd daily-vibe
# Add upstream remote
git remote add upstream https://github.com/AoWangg/daily-vibe.git
# Verify remotes
git remote -v
# Install dependencies (pnpm recommended)
pnpm install
# Or with npm
npm install
# Verify installation
pnpm list
# Build the project
pnpm run build
# Run tests
pnpm test
# Run linting
pnpm run lint
# Link for local development
pnpm link --global
# Test the CLI
daily-vibe --version
Project Structure
daily-vibe/
├── src/ # Source code
│ ├── commands/ # CLI command implementations
│ ├── lib/ # Core library code
│ │ ├── analyzers/ # Analysis engines
│ │ ├── collectors/ # Data source collectors
│ │ ├── config/ # Configuration management
│ │ ├── llm/ # LLM provider integrations
│ │ └── utils/ # Utility functions
│ ├── types/ # TypeScript type definitions
│ └── index.ts # Main entry point
├── tests/ # Test files
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── fixtures/ # Test data
├── docs/ # Documentation
├── scripts/ # Build and utility scripts
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── README.md # Project overview
Development Workflow
Making Changes
- Create a Feature Branch:
# Update main branch
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/your-feature-name
# Or for bug fixes
git checkout -b fix/issue-description
- Make Your Changes:
# Make code changes
# Add tests for new functionality
# Update documentation if needed
# Run tests frequently during development
pnpm test
# Check linting
pnpm run lint
- Commit Your Changes:
# Stage your changes
git add .
# Commit with descriptive message
git commit -m "feat: add support for custom LLM providers"
# Or for bug fixes
git commit -m "fix: resolve authentication timeout issue"
Commit Message Guidelines
Follow Conventional Commits format:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Types:
feat
: A new featurefix
: A bug fixdocs
: Documentation only changesstyle
: Code style changes (formatting, etc.)refactor
: Code refactoringperf
: Performance improvementstest
: Adding or fixing testschore
: Maintenance tasks
Examples:
git commit -m "feat(commands): add weekly analysis command"
git commit -m "fix(collectors): handle missing Claude Code directory"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(analyzers): add unit tests for knowledge extraction"
Code Guidelines
TypeScript Standards
// Use strict typing
interface AnalysisResult {
summary: {
overview: string;
keyOutputs: string[];
};
statistics: {
totalSessions: number;
totalHours: number;
avgSessionLength: number;
};
}
// Prefer type guards
function isValidAnalysisResult(data: unknown): data is AnalysisResult {
return typeof data === 'object' &&
data !== null &&
'summary' in data &&
'statistics' in data;
}
// Use generic constraints
interface DataCollector<T extends SessionData> {
collect(dateRange: DateRange): Promise<T[]>;
}
// Use async/await over Promises
async function analyzeSession(session: SessionData): Promise<AnalysisResult> {
try {
const analysis = await llmProvider.analyze(session.content);
return processAnalysis(analysis);
} catch (error) {
logger.error('Analysis failed:', error);
throw new AnalysisError('Failed to analyze session', { cause: error });
}
}
// Prefer functional programming
const validSessions = sessions
.filter(session => session.duration > minDuration)
.map(session => normalizeSession(session))
.filter(session => session.content.length > 0);
// Use descriptive names
const extractProblemSolutionPairs = (content: string): ProblemSolution[] => {
// Implementation
};
// Create custom error classes
export class ConfigurationError extends Error {
constructor(message: string, public readonly field?: string) {
super(message);
this.name = 'ConfigurationError';
}
}
// Handle errors gracefully
async function loadConfiguration(): Promise<Configuration> {
try {
const config = await cosmiconfig.search();
if (!config) {
throw new ConfigurationError('No configuration file found');
}
return validateConfiguration(config.config);
} catch (error) {
if (error instanceof ConfigurationError) {
throw error;
}
throw new ConfigurationError('Failed to load configuration', { cause: error });
}
}
Testing Guidelines
Write comprehensive tests for new functionality:
// tests/unit/analyzers/knowledge-extractor.test.ts
import { describe, it, expect } from 'vitest';
import { KnowledgeExtractor } from '../../../src/lib/analyzers/knowledge-extractor';
describe('KnowledgeExtractor', () => {
const extractor = new KnowledgeExtractor();
it('should extract problem-solution pairs', () => {
const content = `
I encountered a TypeScript error: Property 'foo' does not exist on type 'Bar'.
I solved it by adding a type assertion: (obj as any).foo
`;
const result = extractor.extractProblemSolution(content);
expect(result).toHaveLength(1);
expect(result[0].problem).toContain('TypeScript error');
expect(result[0].solution).toContain('type assertion');
});
it('should categorize knowledge by tags', () => {
const problemSolution = {
problem: 'React component not re-rendering',
solution: 'Use useCallback hook',
context: 'React functional component'
};
const tags = extractor.generateTags(problemSolution);
expect(tags).toContain('react');
expect(tags).toContain('hooks');
});
});
// tests/integration/commands/analyze.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtemp, rm } from 'fs/promises';
import { join } from 'path';
import { tmpdir } from 'os';
import { AnalyzeCommand } from '../../../src/commands/analyze';
describe('Analyze Command Integration', () => {
let tempDir: string;
beforeEach(async () => {
tempDir = await mkdtemp(join(tmpdir(), 'daily-vibe-test-'));
});
afterEach(async () => {
await rm(tempDir, { recursive: true });
});
it('should generate reports for valid session data', async () => {
// Setup test data
const mockSessions = [
{ timestamp: new Date(), content: 'Test session', duration: 3600 }
];
// Run analysis
const command = new AnalyzeCommand();
await command.run(['today', '--out', tempDir]);
// Verify outputs
const dailyReport = await readFile(join(tempDir, 'daily.md'), 'utf8');
expect(dailyReport).toContain('Daily Development Report');
});
});
// tests/unit/lib/llm/openai-provider.test.ts
import { describe, it, expect, vi } from 'vitest';
import { OpenAIProvider } from '../../../src/lib/llm/openai-provider';
// Mock the OpenAI client
vi.mock('openai', () => ({
default: vi.fn().mockImplementation(() => ({
chat: {
completions: {
create: vi.fn().mockResolvedValue({
choices: [{ message: { content: 'Mock response' } }]
})
}
}
}))
}));
describe('OpenAIProvider', () => {
it('should make API calls with correct parameters', async () => {
const provider = new OpenAIProvider({ apiKey: 'test-key', model: 'gpt-4' });
const result = await provider.analyze('Test content');
expect(result).toBe('Mock response');
});
});
Adding New Features
Adding a New Data Source
To add support for a new data source:
- Create Collector Interface:
// src/lib/collectors/new-source-collector.ts
export interface NewSourceCollector extends DataCollector<NewSourceSession> {
scanDataSources(): Promise<DataSourceInfo[]>;
collectSessions(dateRange: DateRange): Promise<NewSourceSession[]>;
}
export class NewSourceCollectorImpl implements NewSourceCollector {
async scanDataSources(): Promise<DataSourceInfo[]> {
// Implement source scanning logic
}
async collectSessions(dateRange: DateRange): Promise<NewSourceSession[]> {
// Implement session collection logic
}
}
- Register Collector:
// src/lib/collectors/index.ts
import { NewSourceCollectorImpl } from './new-source-collector';
export const collectors = {
claudeCode: new ClaudeCodeCollector(),
codexCli: new CodexCliCollector(),
newSource: new NewSourceCollectorImpl(), // Add here
};
- Add Configuration Support:
// src/lib/config/schema.ts
export const configSchema = z.object({
dataSources: z.object({
newSource: z.object({
enabled: z.boolean().default(true),
paths: z.array(z.string()).optional(),
}).optional(),
}),
});
- Add Tests:
// tests/unit/collectors/new-source-collector.test.ts
describe('NewSourceCollector', () => {
it('should collect sessions from new source', async () => {
// Test implementation
});
});
Adding a New LLM Provider
To add support for a new LLM provider:
- Implement Provider Interface:
// src/lib/llm/new-provider.ts
export class NewLLMProvider implements LLMProvider {
constructor(private config: NewProviderConfig) {}
async analyze(content: string, prompt: string): Promise<string> {
// Implement API call logic
}
async validateConfiguration(): Promise<boolean> {
// Implement configuration validation
}
}
- Register Provider:
// src/lib/llm/factory.ts
export function createLLMProvider(config: LLMConfig): LLMProvider {
switch (config.provider) {
case 'openai':
return new OpenAIProvider(config);
case 'anthropic':
return new AnthropicProvider(config);
case 'new-provider':
return new NewLLMProvider(config); // Add here
default:
throw new Error(`Unsupported provider: ${config.provider}`);
}
}
- Update Configuration Schema:
// src/lib/config/schema.ts
const llmProviderSchema = z.enum(['openai', 'anthropic', 'new-provider']);
Adding a New Command
To add a new CLI command:
- Create Command Class:
// src/commands/new-command.ts
import { Command, Flags } from '@oclif/core';
export default class NewCommand extends Command {
static description = 'Description of your new command';
static flags = {
output: Flags.string({
char: 'o',
description: 'Output directory',
default: './output'
}),
};
async run(): Promise<void> {
const { flags } = await this.parse(NewCommand);
// Command implementation
}
}
- Register Command:
// src/index.ts
export { default as NewCommand } from './commands/new-command';
Documentation
Code Documentation
Use JSDoc for documenting functions and classes:
/**
* Analyzes coding session data and generates insights
*
* @param sessions - Array of session data to analyze
* @param options - Analysis configuration options
* @returns Promise resolving to analysis results
*
* @example
* ```typescript
* const results = await analyzeSession(sessions, {
* includeKnowledge: true,
* redactSensitive: true
* });
* ```
*/
async function analyzeSessions(
sessions: SessionData[],
options: AnalysisOptions
): Promise<AnalysisResult> {
// Implementation
}
Updating Documentation
When adding new features:
- Update README: Add feature descriptions and examples
- Update API Docs: Document new configuration options
- Add Examples: Provide usage examples in
/docs/examples
- Update CLI Help: Ensure command descriptions are clear
Testing
Running Tests
# Run all tests
pnpm test
# Run tests in watch mode during development
pnpm test:watch
# Run tests with verbose output
pnpm test --reporter=verbose
# Run specific test file
pnpm test tests/unit/analyzers/knowledge-extractor.test.ts
# Run tests matching pattern
pnpm test --grep "KnowledgeExtractor"
# Run integration tests only
pnpm test tests/integration/
# Generate coverage report
pnpm test:coverage
# View coverage in browser
open coverage/index.html
Test Environment Setup
For integration tests that require API access:
# Set test environment variables
export DAILY_VIBE_TEST_OPENAI_KEY=your-test-key
export DAILY_VIBE_TEST_ANTHROPIC_KEY=your-test-key
# Or create .env.test file
echo "DAILY_VIBE_TEST_OPENAI_KEY=your-test-key" > .env.test
Contributing Process
Pull Request Guidelines
-
Before Creating PR:
- Ensure all tests pass:
pnpm test
- Check linting:
pnpm run lint
- Update documentation if needed
- Test CLI functionality manually
- Ensure all tests pass:
-
PR Description Template:
## Description Brief description of changes ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update ## Testing - [ ] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing completed ## Checklist - [ ] My code follows the project's style guidelines - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New and existing unit tests pass locally with my changes
-
Review Process:
- Ensure CI checks pass
- Address reviewer feedback promptly
- Keep commits clean and focused
- Squash commits if requested
Code Review Guidelines
When reviewing PRs:
- Functionality: Does the code work as intended?
- Testing: Are there adequate tests?
- Performance: Are there any performance concerns?
- Security: Are there any security implications?
- Maintainability: Is the code readable and maintainable?
- Documentation: Is the code properly documented?
Release Process
Versioning
Daily Vibe follows Semantic Versioning:
- Major (X.0.0): Breaking changes
- Minor (0.X.0): New features (backward compatible)
- Patch (0.0.X): Bug fixes (backward compatible)
Release Steps
- Prepare Release:
# Update version
pnpm version major|minor|patch
# Update CHANGELOG.md
git add CHANGELOG.md
git commit -m "docs: update changelog for v$(cat package.json | jq -r .version)"
# Create release tag
git tag -a v$(cat package.json | jq -r .version) -m "Release v$(cat package.json | jq -r .version)"
- Publish Release:
# Build for production
pnpm run build
# Publish to npm
pnpm publish
# Push tags
git push origin main --tags
Community Guidelines
Code of Conduct
Daily Vibe follows the Contributor Covenant Code of Conduct. Please be respectful and inclusive in all interactions.
Getting Help
- Documentation: Check this documentation first
- Issues: Search existing issues before creating new ones
- Discussions: Use GitHub Discussions for questions
- Discord: Join our Discord community (link in README)
Recognition
Contributors are recognized in:
CONTRIBUTORS.md
file- Release notes for significant contributions
- Annual contributor highlights
Thank you for contributing to Daily Vibe! Your contributions help make development insight generation accessible to everyone.
Next Steps
Ready to contribute? Here's what to do next:
- Set up development environment following the setup guide above
- Find an issue to work on in our GitHub Issues
- Join our community discussions to connect with other contributors
- Start coding and create your first pull request!
We look forward to your contributions! 🚀