Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
cf967d9
refactor(types): delete dead model files (issue/pattern/session)
sebastianwessel Jul 9, 2026
61bce35
refactor(types): unify duplicated root-cause & extract-log types
sebastianwessel Jul 9, 2026
7916d78
refactor(forges): extract duplicated forge-integration contracts to f…
sebastianwessel Jul 9, 2026
d374764
refactor(kernel): introduce kernel/ layer; relocate pure hash utility
sebastianwessel Jul 9, 2026
9efc753
refactor(types): split shared/types/index.ts into domain-focused files
sebastianwessel Jul 9, 2026
345aec1
refactor(types): replace generic primitives.ts with purpose-named files
sebastianwessel Jul 9, 2026
4d7adc7
refactor(report): extract duplicated confidence-badge thresholds to a…
sebastianwessel Jul 9, 2026
c642343
refactor(types): remove dead public-API-only types
sebastianwessel Jul 9, 2026
4ddc304
refactor(pricing): extract TOKENS_PER_MILLION constant
sebastianwessel Jul 9, 2026
0dd2823
refactor: strip narration/redundant comments added during the refactor
sebastianwessel Jul 9, 2026
8025c1b
refactor: rename forges/ to integrations/ (clearer than the "forge" j…
sebastianwessel Jul 9, 2026
34cc19e
refactor: move shared integration contracts to src/shared/integration…
sebastianwessel Jul 9, 2026
41f83a4
refactor: move shared integration contracts to src/shared/types/integ…
sebastianwessel Jul 9, 2026
ec69732
docs(changelog): note the structure/dedup refactor + trimmed public t…
sebastianwessel Jul 9, 2026
ddd7904
Merge remote-tracking branch 'origin/main' into refactor/structure-cl…
sebastianwessel Jul 9, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- `BASH_TOOL_DESCRIPTION` constant removed; callers use `buildBashToolDescription(root)` directly so the description always reflects the actual workspace root rather than a hardcoded `/workspace/pr`.
- Updated all dependencies to their latest stable versions (OpenTelemetry, `openai`, `@openai/agents`, `@types/node`, ESLint + `typescript-eslint`, `jest`/`ts-jest`, `prettier`, `zod`; website: Astro 6→7 + Starlight). Dropped the redundant `@types/diff` stub (diff@9 ships its own types) and pinned transitive `uuid` via `overrides`. Build, lint, type-check, unit tests, and evals all pass.
- Internal structure & de-duplication refactor (no runtime behavior change): centralized duplicated utilities/types, split the `shared/types` barrel into domain-focused files, introduced `src/kernel/` for pure helpers, and extracted shared constants. As part of this, unused types were trimmed from the package's exported type surface — the dead `Issue`/`Pattern`/`Session` model classes and the unreferenced `FilePath`/`SessionId`/`FileContent`/`CodeLocation`/`CodeSnippet`/`Metrics` aliases (no internal or known external use).

### Security
- Reduced dependency vulnerabilities: website advisories fully resolved (8→0); remaining root advisories trace to `@eggai/configurable-agent@0.2.1` (no upstream fix; slated for retirement). Note: the majority of GitHub's Dependabot alerts are frozen third-party eval fixtures under `evals/datasets/`, not shipped dependencies.
Expand Down
10 changes: 6 additions & 4 deletions src/ai/providers/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { logger } from '@/shared/utils/logger';

import type { ProviderCapabilities } from './capabilities';
import { detectCapabilities } from './capabilities';
import { TOKENS_PER_MILLION } from './pricing-constants';
import type {
AICompletionOptions,
AICompletionOptionsWithSchema,
Expand Down Expand Up @@ -139,11 +140,12 @@ export abstract class BaseAIProvider implements AIProvider {
const { inputPerMillion, outputPerMillion } = this.stageConfig;
const { cacheWriteMultiplier, cacheReadMultiplier } = this.pricingMultipliers(use1HourCache);

const inputCost = (fullPriceInput / 1_000_000) * inputPerMillion;
const cacheReadCost = (cachedReadTokens / 1_000_000) * (inputPerMillion * cacheReadMultiplier);
const inputCost = (fullPriceInput / TOKENS_PER_MILLION) * inputPerMillion;
const cacheReadCost =
(cachedReadTokens / TOKENS_PER_MILLION) * (inputPerMillion * cacheReadMultiplier);
const cacheWriteCost =
(cacheCreationTokens / 1_000_000) * (inputPerMillion * cacheWriteMultiplier);
const outputCost = (output / 1_000_000) * outputPerMillion;
(cacheCreationTokens / TOKENS_PER_MILLION) * (inputPerMillion * cacheWriteMultiplier);
const outputCost = (output / TOKENS_PER_MILLION) * outputPerMillion;
this.tokenStats.estimatedCost += inputCost + cacheReadCost + cacheWriteCost + outputCost;

this.logUsageIfDue();
Expand Down
3 changes: 2 additions & 1 deletion src/ai/providers/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { logger } from '@/shared/utils/logger';

import { BaseAIProvider, type PricingMultipliers } from './base';
import { AIProviderType } from './factory';
import { TOKENS_PER_MILLION } from './pricing-constants';
import type {
AICompletionOptions,
AICompletionOptionsWithSchema,
Expand Down Expand Up @@ -135,7 +136,7 @@ export class BedrockProvider extends BaseAIProvider {
if (counters.reads > 0 || counters.writes > 0) {
const hitRate = ((counters.hits / stats.invocationCount) * 100).toFixed(1);
const cacheReadSavings =
(counters.reads / 1_000_000) * (this.stageConfig.inputPerMillion * 0.9);
(counters.reads / TOKENS_PER_MILLION) * (this.stageConfig.inputPerMillion * 0.9);
msg += `, CacheWrite=${counters.writes.toLocaleString()}`;
msg += `, CacheRead=${counters.reads.toLocaleString()} (${hitRate}% hit rate)`;
msg += `, CacheSavings=$${cacheReadSavings.toFixed(4)}`;
Expand Down
1 change: 1 addition & 0 deletions src/ai/providers/pricing-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const TOKENS_PER_MILLION = 1_000_000;
3 changes: 2 additions & 1 deletion src/cli/commands/all-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Span, Tracer } from '@opentelemetry/api';

import { executeAnalyzeStage } from './analyze-command';
import { executeFixStage } from './fix-command';
import { TOKENS_PER_MILLION } from '../../ai/providers/pricing-constants';
import { ConfigService, DEFAULT_CONFIG_PATH } from '../../config/config';
import {
setupTracing,
Expand Down Expand Up @@ -71,7 +72,7 @@ export async function executeAllStages(options: QualOpsOptions): Promise<void> {
logger.info(`Output Tokens: ${totalStats.totalOutputTokens.toLocaleString()}`);
if (totalStats.totalCachedTokens > 0) {
logger.info(`Cached Tokens: ${totalStats.totalCachedTokens.toLocaleString()}`);
const savings = (totalStats.totalCachedTokens / 1_000_000) * 1.25;
const savings = (totalStats.totalCachedTokens / TOKENS_PER_MILLION) * 1.25;
logger.info(`Cache Savings: $${savings.toFixed(4)}`);
}
logger.info('\nBy Stage:');
Expand Down
36 changes: 6 additions & 30 deletions src/github/github-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { join } from 'path';

import { GitHubAPIClient } from './github-api-client';
import { GitHubChecksService } from './github-checks';
import {
QUALOPS_COMMENT_MARKER,
type IntegrationReviewIssue,
type QualOpsResult,
} from '../shared/types/integrations';
import { logger } from '../shared/utils/logger';

const QUALOPS_COMMENT_MARKER = '<!-- qualops-analysis-comment -->';

interface GitHubConfig {
enabled?: boolean;
postComments?: boolean;
Expand All @@ -31,33 +34,6 @@ interface GitHubEnv {
GITHUB_SERVER_URL?: string;
}

interface QualOpsResult {
summary: {
totalIssues: number;
criticalSeverity: number;
highSeverity: number;
mediumSeverity: number;
lowSeverity: number;
filesAnalyzed: number;
};
reportPath: string;
issues: Array<{
file: string;
line: number;
severity: string;
message: string;
category: string;
}>;
}

interface ReviewIssue {
file: string;
location: string;
severity: string;
description: string;
type: string;
}

interface PullRequestEvent {
pull_request: {
number: number;
Expand Down Expand Up @@ -241,7 +217,7 @@ export class GitHubIntegration {
try {
const reviewSummary = JSON.parse(readFileSync(reviewSummaryPath, 'utf8'));
const summary = reviewSummary.summary || {};
const issues: ReviewIssue[] = reviewSummary.issues || [];
const issues: IntegrationReviewIssue[] = reviewSummary.issues || [];

return {
summary: {
Expand Down
36 changes: 6 additions & 30 deletions src/gitlab/gitlab-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import { existsSync, readdirSync, readFileSync } from 'fs';
import { join } from 'path';

import {
QUALOPS_COMMENT_MARKER,
type IntegrationReviewIssue,
type QualOpsResult,
} from '../shared/types/integrations';
import { logger } from '../shared/utils/logger';
import { hasValidUrlScheme, isValidGitSha } from '../shared/utils/security';

Expand All @@ -13,8 +18,6 @@ const SEVERITY_EMOJI = {
low: '🟢',
} as const;

const QUALOPS_COMMENT_MARKER = '<!-- qualops-analysis-comment -->';

interface GitLabConfig {
enabled?: boolean;
postComments?: boolean;
Expand Down Expand Up @@ -43,25 +46,6 @@ interface GitLabEnv {
CI_PROJECT_URL?: string;
}

interface QualOpsResult {
summary: {
totalIssues: number;
criticalSeverity: number;
highSeverity: number;
mediumSeverity: number;
lowSeverity: number;
filesAnalyzed: number;
};
reportPath: string;
issues: Array<{
file: string;
line: number;
severity: string;
message: string;
category: string;
}>;
}

interface GitLabJob {
id: number;
name: string;
Expand All @@ -75,14 +59,6 @@ interface GitLabNote {
};
}

interface ReviewIssue {
file: string;
location: string;
severity: string;
description: string;
type: string;
}

class GitLabIntegration {
private env: GitLabEnv;
private apiUrl: string;
Expand Down Expand Up @@ -602,7 +578,7 @@ class GitLabIntegration {

if (reviewReport.issues && Array.isArray(reviewReport.issues)) {
// Transform issues to match expected format
const transformedIssues = reviewReport.issues.map((issue: ReviewIssue) => {
const transformedIssues = reviewReport.issues.map((issue: IntegrationReviewIssue) => {
// Parse location field - handle both "42" and "line:42" formats
const locationStr = issue.location.replace(/^line:?/i, '').trim();
const lineNumber = parseInt(locationStr, 10) || 0;
Expand Down
File renamed without changes.
63 changes: 63 additions & 0 deletions src/shared/types/ai-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { z } from 'zod';

import type { aiProvider, modelConfigSchema } from '@/config/config-schema';

import type { ReviewConfig } from './config';

export type AIProviderName = z.infer<typeof aiProvider>;

export type ModelConfig = z.infer<typeof modelConfigSchema>;

export type AIStageConfig = {
provider?: AIProviderName; // deprecated fallback; prefer model: { provider, name }
model: ModelConfig;
inputPerMillion: number;
outputPerMillion: number;
temperature?: number;
maxTokens?: number;
baseUrl?: string;
[key: string]: unknown;
};

export type ResolvedStageConfig = {
provider: AIProviderName;
model: string;
inputPerMillion: number;
outputPerMillion: number;
temperature?: number;
maxTokens?: number;
baseUrl?: string;
[key: string]: unknown;
};

export type Config = {
ai?: {
reviewStage?: AIStageConfig;
fixStage?: AIStageConfig;
judgeStage?: AIStageConfig;
};
review?: ReviewConfig;
fix?: {
maxConcurrentFixes: number;
};
report?: {
generateIssueMarkdown?: boolean;
enableRootCauseExtraction?: boolean;
};
maxFilesPerBatch?: number;
maxConcurrency?: number;
cacheEnabled?: boolean;
cacheTTL?: number;
skipPatterns?: string[];
includePatterns?: string[];
outputFormat?: 'json' | 'html' | 'markdown';
outputPath?: string;
verbose?: boolean;
debug?: boolean;
maxFileSizeKB?: number;
maxTokensPerFile?: number;
maxReactSteps?: number;
throttling?: {
apiCallsPerMinute: number;
};
};
24 changes: 24 additions & 0 deletions src/shared/types/analysis-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface AnalysisMetadata {
timestamp: string;
filePaths: string[];
dependencies?: Record<string, string[]>;
executionTime?: number;
gitRefs?: {
base: string;
head: string;
};
}

export interface ExtractLog {
timestamp: string;
files: Record<
string,
{
hash: string;
size: number;
lastModified: string;
processed: boolean;
}
>;
[key: string]: unknown;
}
34 changes: 34 additions & 0 deletions src/shared/types/finding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export interface ReviewIssue {
id: string;
file: string;
line?: number;
type: 'bug' | 'security' | 'performance' | 'maintainability';
severity: 'critical' | 'high' | 'medium' | 'low';
category?: string;
description: string;
location: string;
reasoning: string;
suggestion: string;
context: string;
confidence: number;
tags?: string[];
priority?: number;
estimatedEffort?: 'low' | 'medium' | 'high';
knowledge_source?: string;
impact?: string;
cwe?: string;
threat_model?: string;
validation_reasoning?: string;
}

export interface FixSuggestion {
issueId: string;
file: string;
line: number;
originalCode: string;
suggestedCode: string;
explanation: string;
confidence: 'high' | 'medium' | 'low';
breaking: boolean;
applied: boolean;
}
15 changes: 15 additions & 0 deletions src/shared/types/fix-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { FixSuggestion } from './finding';

export interface FixMetadata {
timestamp: string;
issuesProcessed: number;
suggestions: FixSuggestion[];
summary: {
totalSuggestions: number;
highConfidence: number;
mediumConfidence: number;
lowConfidence: number;
breaking: number;
applied: number;
};
}
6 changes: 6 additions & 0 deletions src/shared/types/framework-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface FrameworkContext {

Check warning on line 1 in src/shared/types/framework-context.ts

View workflow job for this annotation

GitHub Actions / QualOps Code Quality

MEDIUM: maintainability

Duplicate `FrameworkContext` interface: the new canonical `shared/types/framework-context.ts` has stricter types than the existing one in `shared/utils/documentation-context.ts`, creating two divergent definitions
framework: 'angular' | 'react' | 'nodejs' | 'typescript';
version?: string;
dependencies: string[];
fileType?: 'service' | 'component' | 'guard' | 'pipe' | 'directive';
}
Loading
Loading