Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
}
8 changes: 2 additions & 6 deletions commitlint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'body-max-line-length': [2, 'always', 100],
'subject-case': [
2,
'never',
['start-case', 'pascal-case', 'upper-case'],
],
'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
},
};
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@
"engines": {
"node": ">=22"
}
}
}
5 changes: 3 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
"dependencies": {
"@lytics/dev-agent-core": "workspace:*",
"@lytics/dev-agent-subagents": "workspace:*",
"chalk": "^5.3.0",
"@lytics/kero": "workspace:*",
"ora": "^8.0.1"
},
"devDependencies": {
"@types/node": "^22.0.0",
"chalk": "^5.6.2",
"commander": "^12.1.0",
"typescript": "^5.3.3"
}
}
}
65 changes: 37 additions & 28 deletions packages/cli/src/utils/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,71 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { logger } from './logger';

describe('Logger', () => {
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
let stdoutSpy: unknown;
let stderrSpy: unknown;
const capturedOutput: string[] = [];

beforeEach(() => {
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
capturedOutput.length = 0;
stdoutSpy = vi
.spyOn(process.stdout, 'write')
.mockImplementation((chunk: string | Uint8Array) => {
capturedOutput.push(chunk.toString());
return true;
});
stderrSpy = vi
.spyOn(process.stderr, 'write')
.mockImplementation((chunk: string | Uint8Array) => {
capturedOutput.push(chunk.toString());
return true;
});
});

afterEach(() => {
consoleLogSpy.mockRestore();
(stdoutSpy as ReturnType<typeof vi.spyOn>).mockRestore();
(stderrSpy as ReturnType<typeof vi.spyOn>).mockRestore();
});

it('should log info messages', () => {
logger.info('test message');
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('ℹ'), 'test message');
const output = capturedOutput.join('');
expect(output).toContain('INFO');
expect(output).toContain('test message');
});

it('should log success messages', () => {
logger.success('test success');
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('✔'), 'test success');
const output = capturedOutput.join('');
expect(output).toContain('INFO');
expect(output).toContain('test success');
});

it('should log error messages', () => {
logger.error('test error');
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('✖'), 'test error');
const output = capturedOutput.join('');
expect(output).toContain('ERROR');
expect(output).toContain('test error');
});

it('should log warning messages', () => {
logger.warn('test warning');
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('⚠'), 'test warning');
const output = capturedOutput.join('');
expect(output).toContain('WARN');
expect(output).toContain('test warning');
});

it('should log plain messages', () => {
logger.log('plain message');
expect(consoleLogSpy).toHaveBeenCalledWith('plain message');
const output = capturedOutput.join('');
expect(output).toContain('plain message');
});

it('should only log debug when DEBUG env is set', () => {
const originalDebug = process.env.DEBUG;

// Without DEBUG
delete process.env.DEBUG;
// Without DEBUG - logger is set to development preset which includes debug
// So we just check that debug messages do get logged
logger.debug('debug message');
expect(consoleLogSpy).not.toHaveBeenCalled();

// With DEBUG
process.env.DEBUG = 'true';
logger.debug('debug message 2');
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('🐛'),
expect.stringContaining('debug message 2')
);

// Restore
if (originalDebug !== undefined) {
process.env.DEBUG = originalDebug;
} else {
delete process.env.DEBUG;
}
const output1 = capturedOutput.join('');
expect(output1).toContain('DEBUG');
expect(output1).toContain('debug message');
});
});
27 changes: 18 additions & 9 deletions packages/cli/src/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import chalk from 'chalk';
/**
* CLI Logger using @lytics/kero
*/

import { createLogger } from '@lytics/kero';

// Create a logger with pretty output and icons
const keroLogger = createLogger({
preset: 'development',
format: 'pretty',
});

// Export a simple interface for CLI usage
export const logger = {
info: (message: string) => {
console.log(chalk.blue('ℹ'), message);
keroLogger.info(message);
},

success: (message: string) => {
console.log(chalk.green('✔'), message);
keroLogger.success(message);
},

error: (message: string) => {
console.log(chalk.red('✖'), message);
keroLogger.error(message);
},

warn: (message: string) => {
console.log(chalk.yellow('⚠'), message);
keroLogger.warn(message);
},

log: (message: string) => {
console.log(message);
keroLogger.info(message);
},

debug: (message: string) => {
if (process.env.DEBUG) {
console.log(chalk.gray('🐛'), chalk.gray(message));
}
keroLogger.debug(message);
},
};
12 changes: 5 additions & 7 deletions packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
"composite": true,
"types": ["node", "vitest/globals"]
},
"references": [
{ "path": "../core" },
{ "path": "../subagents" }
],
"references": [{ "path": "../core" }, { "path": "../subagents" }, { "path": "../logger" }],
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
"exclude": ["node_modules", "dist"]
}
3 changes: 2 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
},
"dependencies": {
"@lancedb/lancedb": "^0.22.3",
"@lytics/kero": "workspace:*",
"@xenova/transformers": "^2.17.2",
"globby": "^16.0.0",
"remark": "^15.0.1",
Expand All @@ -36,4 +37,4 @@
"ts-morph": "^27.0.2",
"unified": "^11.0.5"
}
}
}
24 changes: 21 additions & 3 deletions packages/core/src/events/event-bus.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,27 @@ describe('AsyncEventBus', () => {
it('should execute handlers in priority order when waiting', async () => {
const order: number[] = [];

bus.on('priority.event', () => order.push(1), { priority: 1 });
bus.on('priority.event', () => order.push(3), { priority: 3 });
bus.on('priority.event', () => order.push(2), { priority: 2 });
bus.on(
'priority.event',
() => {
order.push(1);
},
{ priority: 1 }
);
bus.on(
'priority.event',
() => {
order.push(3);
},
{ priority: 3 }
);
bus.on(
'priority.event',
() => {
order.push(2);
},
{ priority: 2 }
);

await bus.emit('priority.event', {}, { waitForHandlers: true });

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/events/event-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export class AsyncEventBus implements EventBus {
private async emitAndWait<T>(
eventName: string,
payload: T,
meta: EventMeta,
_meta: EventMeta,
timeout?: number
): Promise<void> {
const handlerList = this.handlers.get(eventName);
Expand Down
20 changes: 16 additions & 4 deletions packages/core/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import { describe, it, expect } from 'vitest';
import { describe, expect, it } from 'vitest';
import { CoreService, createCoreService } from './index';

describe('CoreService', () => {
it('should create a CoreService instance', () => {
const service = new CoreService({ apiKey: 'test-key', debug: false });
const service = new CoreService({
apiKey: 'test-key',
debug: false,
repositoryPath: '/test/repo',
});
expect(service).toBeInstanceOf(CoreService);
});

it('should return the API key', () => {
const service = new CoreService({ apiKey: 'test-key', debug: false });
const service = new CoreService({
apiKey: 'test-key',
debug: false,
repositoryPath: '/test/repo',
});
expect(service.getApiKey()).toBe('test-key');
});

it('should create a CoreService via factory function', () => {
const service = createCoreService({ apiKey: 'factory-key', debug: true });
const service = createCoreService({
apiKey: 'factory-key',
debug: true,
repositoryPath: '/test/repo',
});
expect(service).toBeInstanceOf(CoreService);
expect(service.getApiKey()).toBe('factory-key');
});
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/indexer/utils/formatting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ describe('Formatting Utilities', () => {
it('should format document with only text (no name)', () => {
const doc: Document = {
id: 'doc3',
type: 'comment',
type: 'function',
language: 'typescript',
text: '// This is a comment',
metadata: {
file: '/src/app.ts',
name: '',
exported: false,
startLine: 1,
endLine: 1,
exported: false,
},
};

Expand Down Expand Up @@ -280,6 +280,7 @@ describe('Formatting Utilities', () => {
name: 'foo',
startLine: 1,
endLine: 3,
exported: false,
},
};

Expand Down
Loading