@levironexe/architect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +55 -0
- package/README.md +341 -0
- package/dist/analyzers/ast-parser.d.ts +3 -0
- package/dist/analyzers/ast-parser.js +305 -0
- package/dist/analyzers/ast-parser.js.map +1 -0
- package/dist/analyzers/dependency-graph.d.ts +2 -0
- package/dist/analyzers/dependency-graph.js +67 -0
- package/dist/analyzers/dependency-graph.js.map +1 -0
- package/dist/analyzers/duplication.d.ts +2 -0
- package/dist/analyzers/duplication.js +56 -0
- package/dist/analyzers/duplication.js.map +1 -0
- package/dist/analyzers/file-walker.d.ts +3 -0
- package/dist/analyzers/file-walker.js +80 -0
- package/dist/analyzers/file-walker.js.map +1 -0
- package/dist/cli/context-runner.d.ts +1 -0
- package/dist/cli/context-runner.js +16 -0
- package/dist/cli/context-runner.js.map +1 -0
- package/dist/cli/index.d.ts +24 -0
- package/dist/cli/index.js +217 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-runner.d.ts +25 -0
- package/dist/cli/init-runner.js +152 -0
- package/dist/cli/init-runner.js.map +1 -0
- package/dist/cli/scan-runner.d.ts +8 -0
- package/dist/cli/scan-runner.js +133 -0
- package/dist/cli/scan-runner.js.map +1 -0
- package/dist/formatters/plan-json.d.ts +2 -0
- package/dist/formatters/plan-json.js +4 -0
- package/dist/formatters/plan-json.js.map +1 -0
- package/dist/formatters/plan-markdown.d.ts +2 -0
- package/dist/formatters/plan-markdown.js +42 -0
- package/dist/formatters/plan-markdown.js.map +1 -0
- package/dist/formatters/plan-prompt.d.ts +4 -0
- package/dist/formatters/plan-prompt.js +5 -0
- package/dist/formatters/plan-prompt.js.map +1 -0
- package/dist/formatters/plan-terminal.d.ts +5 -0
- package/dist/formatters/plan-terminal.js +62 -0
- package/dist/formatters/plan-terminal.js.map +1 -0
- package/dist/generators/blueprint-renderer.d.ts +3 -0
- package/dist/generators/blueprint-renderer.js +27 -0
- package/dist/generators/blueprint-renderer.js.map +1 -0
- package/dist/generators/claudeWriter.d.ts +3 -0
- package/dist/generators/claudeWriter.js +9 -0
- package/dist/generators/claudeWriter.js.map +1 -0
- package/dist/generators/copilotWriter.d.ts +3 -0
- package/dist/generators/copilotWriter.js +11 -0
- package/dist/generators/copilotWriter.js.map +1 -0
- package/dist/generators/cursorWriter.d.ts +3 -0
- package/dist/generators/cursorWriter.js +14 -0
- package/dist/generators/cursorWriter.js.map +1 -0
- package/dist/generators/genericWriter.d.ts +3 -0
- package/dist/generators/genericWriter.js +9 -0
- package/dist/generators/genericWriter.js.map +1 -0
- package/dist/generators/template-context.d.ts +18 -0
- package/dist/generators/template-context.js +126 -0
- package/dist/generators/template-context.js.map +1 -0
- package/dist/generators/templateRenderer.d.ts +2 -0
- package/dist/generators/templateRenderer.js +19 -0
- package/dist/generators/templateRenderer.js.map +1 -0
- package/dist/generators/windsurfWriter.d.ts +3 -0
- package/dist/generators/windsurfWriter.js +14 -0
- package/dist/generators/windsurfWriter.js.map +1 -0
- package/dist/generators/writer-types.d.ts +11 -0
- package/dist/generators/writer-types.js +40 -0
- package/dist/generators/writer-types.js.map +1 -0
- package/dist/llm/claude-provider.d.ts +8 -0
- package/dist/llm/claude-provider.js +22 -0
- package/dist/llm/claude-provider.js.map +1 -0
- package/dist/llm/concern-classifier.d.ts +15 -0
- package/dist/llm/concern-classifier.js +61 -0
- package/dist/llm/concern-classifier.js.map +1 -0
- package/dist/llm/config.d.ts +11 -0
- package/dist/llm/config.js +120 -0
- package/dist/llm/config.js.map +1 -0
- package/dist/llm/ollama-provider.d.ts +8 -0
- package/dist/llm/ollama-provider.js +27 -0
- package/dist/llm/ollama-provider.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +8 -0
- package/dist/llm/openai-provider.js +19 -0
- package/dist/llm/openai-provider.js.map +1 -0
- package/dist/llm/prompt-builder.d.ts +12 -0
- package/dist/llm/prompt-builder.js +132 -0
- package/dist/llm/prompt-builder.js.map +1 -0
- package/dist/llm/provider.d.ts +17 -0
- package/dist/llm/provider.js +2 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/response-parser.d.ts +6 -0
- package/dist/llm/response-parser.js +128 -0
- package/dist/llm/response-parser.js.map +1 -0
- package/dist/planner/plan-generator.d.ts +7 -0
- package/dist/planner/plan-generator.js +275 -0
- package/dist/planner/plan-generator.js.map +1 -0
- package/dist/planner/plan-prompt-builder.d.ts +9 -0
- package/dist/planner/plan-prompt-builder.js +92 -0
- package/dist/planner/plan-prompt-builder.js.map +1 -0
- package/dist/planner/plan-response-parser.d.ts +7 -0
- package/dist/planner/plan-response-parser.js +21 -0
- package/dist/planner/plan-response-parser.js.map +1 -0
- package/dist/planner/plan-validator.d.ts +3 -0
- package/dist/planner/plan-validator.js +49 -0
- package/dist/planner/plan-validator.js.map +1 -0
- package/dist/reporters/scan-json.d.ts +13 -0
- package/dist/reporters/scan-json.js +26 -0
- package/dist/reporters/scan-json.js.map +1 -0
- package/dist/reporters/terminal.d.ts +6 -0
- package/dist/reporters/terminal.js +224 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/scoring/consistency-score.d.ts +3 -0
- package/dist/scoring/consistency-score.js +23 -0
- package/dist/scoring/consistency-score.js.map +1 -0
- package/dist/scoring/duplication-score.d.ts +3 -0
- package/dist/scoring/duplication-score.js +16 -0
- package/dist/scoring/duplication-score.js.map +1 -0
- package/dist/scoring/health-score.d.ts +4 -0
- package/dist/scoring/health-score.js +20 -0
- package/dist/scoring/health-score.js.map +1 -0
- package/dist/scoring/issue-builder.d.ts +4 -0
- package/dist/scoring/issue-builder.js +62 -0
- package/dist/scoring/issue-builder.js.map +1 -0
- package/dist/scoring/modularity-score.d.ts +3 -0
- package/dist/scoring/modularity-score.js +56 -0
- package/dist/scoring/modularity-score.js.map +1 -0
- package/dist/scoring/pattern-analysis.d.ts +3 -0
- package/dist/scoring/pattern-analysis.js +74 -0
- package/dist/scoring/pattern-analysis.js.map +1 -0
- package/dist/scoring/separation-score.d.ts +3 -0
- package/dist/scoring/separation-score.js +35 -0
- package/dist/scoring/separation-score.js.map +1 -0
- package/dist/skills/detector.d.ts +4 -0
- package/dist/skills/detector.js +104 -0
- package/dist/skills/detector.js.map +1 -0
- package/dist/skills/lister.d.ts +9 -0
- package/dist/skills/lister.js +35 -0
- package/dist/skills/lister.js.map +1 -0
- package/dist/skills/loader.d.ts +6 -0
- package/dist/skills/loader.js +76 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/structure-check.d.ts +2 -0
- package/dist/skills/structure-check.js +37 -0
- package/dist/skills/structure-check.js.map +1 -0
- package/dist/skills/validator.d.ts +6 -0
- package/dist/skills/validator.js +229 -0
- package/dist/skills/validator.js.map +1 -0
- package/dist/types/analysis.d.ts +130 -0
- package/dist/types/analysis.js +41 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/concern.d.ts +48 -0
- package/dist/types/concern.js +16 -0
- package/dist/types/concern.js.map +1 -0
- package/dist/types/generation.d.ts +32 -0
- package/dist/types/generation.js +2 -0
- package/dist/types/generation.js.map +1 -0
- package/dist/types/issue.d.ts +12 -0
- package/dist/types/issue.js +2 -0
- package/dist/types/issue.js.map +1 -0
- package/dist/types/pattern.d.ts +15 -0
- package/dist/types/pattern.js +2 -0
- package/dist/types/pattern.js.map +1 -0
- package/dist/types/plan.d.ts +56 -0
- package/dist/types/plan.js +2 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/scan-output.d.ts +84 -0
- package/dist/types/scan-output.js +2 -0
- package/dist/types/scan-output.js.map +1 -0
- package/dist/types/scoring.d.ts +15 -0
- package/dist/types/scoring.js +2 -0
- package/dist/types/scoring.js.map +1 -0
- package/dist/types/skill.d.ts +97 -0
- package/dist/types/skill.js +2 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/utils/agent-detector.d.ts +2 -0
- package/dist/utils/agent-detector.js +22 -0
- package/dist/utils/agent-detector.js.map +1 -0
- package/dist/utils/interactive.d.ts +6 -0
- package/dist/utils/interactive.js +15 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/path.d.ts +5 -0
- package/dist/utils/path.js +31 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/progress.d.ts +17 -0
- package/dist/utils/progress.js +48 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/thresholds.d.ts +6 -0
- package/dist/utils/thresholds.js +48 -0
- package/dist/utils/thresholds.js.map +1 -0
- package/package.json +63 -0
- package/skills/meta/general-js.skill.yaml +131 -0
- package/skills/patterns/clerk-auth.skill.yaml +349 -0
- package/skills/patterns/docker-deploy.skill.yaml +214 -0
- package/skills/patterns/drizzle.skill.yaml +277 -0
- package/skills/patterns/mongoose.skill.yaml +290 -0
- package/skills/patterns/nextauth.skill.yaml +308 -0
- package/skills/patterns/playwright-e2e.skill.yaml +265 -0
- package/skills/patterns/prisma.skill.yaml +255 -0
- package/skills/patterns/s3-storage.skill.yaml +235 -0
- package/skills/patterns/selenium-e2e.skill.yaml +276 -0
- package/skills/patterns/supabase-auth.skill.yaml +298 -0
- package/skills/patterns/supabase.skill.yaml +304 -0
- package/skills/patterns/vercel-deploy.skill.yaml +219 -0
- package/skills/patterns/vitest-testing.skill.yaml +262 -0
- package/skills/stacks/express-api.skill.yaml +155 -0
- package/skills/stacks/fastify-api.skill.yaml +119 -0
- package/skills/stacks/hono-api.skill.yaml +130 -0
- package/skills/stacks/nestjs.skill.yaml +135 -0
- package/skills/stacks/nextjs-app-router.skill.yaml +176 -0
- package/skills/stacks/react-spa.skill.yaml +153 -0
- package/skills/stacks/vue-nuxt.skill.yaml +115 -0
- package/templates/architect-plan.md +139 -0
- package/templates/architect-refactor.md +119 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ClaudeProvider } from './claude-provider.js';
|
|
2
|
+
import { OllamaProvider } from './ollama-provider.js';
|
|
3
|
+
import { OpenAIProvider } from './openai-provider.js';
|
|
4
|
+
const DEFAULT_CLAUDE_MODEL = 'claude-3-5-sonnet-latest';
|
|
5
|
+
const DEFAULT_OPENAI_MODEL = 'gpt-4o-mini';
|
|
6
|
+
const DEFAULT_OLLAMA_MODEL = 'llama3.1';
|
|
7
|
+
export function resolveLLMProvider(options = {}) {
|
|
8
|
+
if (options.provider) {
|
|
9
|
+
return {
|
|
10
|
+
config: {
|
|
11
|
+
provider: 'none',
|
|
12
|
+
model: 'mock',
|
|
13
|
+
source: 'explicit',
|
|
14
|
+
isAvailable: true,
|
|
15
|
+
warnings: []
|
|
16
|
+
},
|
|
17
|
+
provider: options.provider
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const env = options.env ?? process.env;
|
|
21
|
+
const requestedProvider = options.explicitProvider ?? parseProviderName(env.ARCHITECT_LLM_PROVIDER);
|
|
22
|
+
if (requestedProvider) {
|
|
23
|
+
return resolveRequestedProvider(requestedProvider, env);
|
|
24
|
+
}
|
|
25
|
+
if (env.ANTHROPIC_API_KEY) {
|
|
26
|
+
const model = env.ANTHROPIC_MODEL ?? DEFAULT_CLAUDE_MODEL;
|
|
27
|
+
return createAvailableResolution('claude', model, new ClaudeProvider(env.ANTHROPIC_API_KEY, model));
|
|
28
|
+
}
|
|
29
|
+
if (env.OPENAI_API_KEY) {
|
|
30
|
+
const model = env.OPENAI_MODEL ?? DEFAULT_OPENAI_MODEL;
|
|
31
|
+
return createAvailableResolution('openai', model, new OpenAIProvider(env.OPENAI_API_KEY, model));
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
config: {
|
|
35
|
+
provider: 'none',
|
|
36
|
+
source: 'fallback',
|
|
37
|
+
isAvailable: false,
|
|
38
|
+
warnings: ['No AI provider configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY, use --provider ollama, or run with --provider none for metrics-only mode.']
|
|
39
|
+
},
|
|
40
|
+
provider: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function resolveRequestedProvider(provider, env) {
|
|
44
|
+
if (provider === 'none') {
|
|
45
|
+
return {
|
|
46
|
+
config: {
|
|
47
|
+
provider: 'none',
|
|
48
|
+
source: 'explicit',
|
|
49
|
+
isAvailable: false,
|
|
50
|
+
warnings: ['AI concern classification disabled. Running metrics-only mode because --provider none was selected.']
|
|
51
|
+
},
|
|
52
|
+
provider: null
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (provider === 'claude') {
|
|
56
|
+
if (!env.ANTHROPIC_API_KEY) {
|
|
57
|
+
return createUnavailableResolution('claude', 'ANTHROPIC_API_KEY is not configured.');
|
|
58
|
+
}
|
|
59
|
+
const model = env.ANTHROPIC_MODEL ?? DEFAULT_CLAUDE_MODEL;
|
|
60
|
+
return createAvailableResolution('claude', model, new ClaudeProvider(env.ANTHROPIC_API_KEY, model));
|
|
61
|
+
}
|
|
62
|
+
if (provider === 'openai') {
|
|
63
|
+
if (!env.OPENAI_API_KEY) {
|
|
64
|
+
return createUnavailableResolution('openai', 'OPENAI_API_KEY is not configured.');
|
|
65
|
+
}
|
|
66
|
+
const model = env.OPENAI_MODEL ?? DEFAULT_OPENAI_MODEL;
|
|
67
|
+
return createAvailableResolution('openai', model, new OpenAIProvider(env.OPENAI_API_KEY, model));
|
|
68
|
+
}
|
|
69
|
+
const model = env.OLLAMA_MODEL ?? DEFAULT_OLLAMA_MODEL;
|
|
70
|
+
return createAvailableResolution('ollama', model, new OllamaProvider(model, env.OLLAMA_BASE_URL));
|
|
71
|
+
}
|
|
72
|
+
function createAvailableResolution(provider, model, llmProvider) {
|
|
73
|
+
return {
|
|
74
|
+
config: {
|
|
75
|
+
provider,
|
|
76
|
+
model,
|
|
77
|
+
source: 'environment',
|
|
78
|
+
isAvailable: true,
|
|
79
|
+
warnings: []
|
|
80
|
+
},
|
|
81
|
+
provider: llmProvider
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function createUnavailableResolution(provider, warning) {
|
|
85
|
+
return {
|
|
86
|
+
config: {
|
|
87
|
+
provider,
|
|
88
|
+
source: 'environment',
|
|
89
|
+
isAvailable: false,
|
|
90
|
+
warnings: [sanitizeProviderWarning(warning)]
|
|
91
|
+
},
|
|
92
|
+
provider: null
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function sanitizeProviderWarning(warning) {
|
|
96
|
+
return warning
|
|
97
|
+
.replace(/sk-[A-Za-z0-9_-]+/g, '[redacted]')
|
|
98
|
+
.replace(/anthropic-[A-Za-z0-9_-]+/g, '[redacted]')
|
|
99
|
+
.replace(/(api[_-]?key\s*[=:]\s*)\S+/gi, '$1[redacted]')
|
|
100
|
+
.replace(/(authorization\s*[:=]\s*bearer\s+)\S+/gi, '$1[redacted]');
|
|
101
|
+
}
|
|
102
|
+
export function parseProviderName(value) {
|
|
103
|
+
if (!value) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const normalized = value.toLowerCase();
|
|
107
|
+
return normalized === 'claude' || normalized === 'openai' || normalized === 'ollama' || normalized === 'none'
|
|
108
|
+
? normalized
|
|
109
|
+
: undefined;
|
|
110
|
+
}
|
|
111
|
+
export function parseProviderOption(value) {
|
|
112
|
+
if (!value) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return parseProviderName(value);
|
|
116
|
+
}
|
|
117
|
+
export function supportedProviderList() {
|
|
118
|
+
return 'claude, openai, ollama, none';
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/llm/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMProvider } from './provider.js';
|
|
2
|
+
export declare class OllamaProvider implements LLMProvider {
|
|
3
|
+
private readonly model;
|
|
4
|
+
readonly name = "Ollama";
|
|
5
|
+
private readonly baseUrl;
|
|
6
|
+
constructor(model: string, baseUrl?: string);
|
|
7
|
+
analyze(prompt: string): Promise<string>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class OllamaProvider {
|
|
2
|
+
model;
|
|
3
|
+
name = 'Ollama';
|
|
4
|
+
baseUrl;
|
|
5
|
+
constructor(model, baseUrl = 'http://localhost:11434') {
|
|
6
|
+
this.model = model;
|
|
7
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
8
|
+
}
|
|
9
|
+
async analyze(prompt) {
|
|
10
|
+
const response = await fetch(`${this.baseUrl}/api/generate`, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: { 'content-type': 'application/json' },
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
model: this.model,
|
|
15
|
+
prompt,
|
|
16
|
+
stream: false,
|
|
17
|
+
format: 'json'
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`Ollama request failed with status ${response.status}`);
|
|
22
|
+
}
|
|
23
|
+
const body = (await response.json());
|
|
24
|
+
return (body.response ?? body.message?.content ?? '').trim();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ollama-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-provider.js","sourceRoot":"","sources":["../../src/llm/ollama-provider.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,cAAc;IAII;IAHb,IAAI,GAAG,QAAQ,CAAC;IACf,OAAO,CAAS;IAEjC,YAA6B,KAAa,EAAE,OAAO,GAAG,wBAAwB;QAAjD,UAAK,GAAL,KAAK,CAAQ;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,eAAe,EAAE;YAC3D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM;gBACN,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,MAAM;aACf,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAmB,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMProvider } from './provider.js';
|
|
2
|
+
export declare class OpenAIProvider implements LLMProvider {
|
|
3
|
+
private readonly model;
|
|
4
|
+
readonly name = "OpenAI";
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(apiKey: string, model: string);
|
|
7
|
+
analyze(prompt: string): Promise<string>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
export class OpenAIProvider {
|
|
3
|
+
model;
|
|
4
|
+
name = 'OpenAI';
|
|
5
|
+
client;
|
|
6
|
+
constructor(apiKey, model) {
|
|
7
|
+
this.model = model;
|
|
8
|
+
this.client = new OpenAI({ apiKey });
|
|
9
|
+
}
|
|
10
|
+
async analyze(prompt) {
|
|
11
|
+
const response = await this.client.chat.completions.create({
|
|
12
|
+
model: this.model,
|
|
13
|
+
messages: [{ role: 'user', content: prompt }],
|
|
14
|
+
temperature: 0
|
|
15
|
+
});
|
|
16
|
+
return response.choices[0]?.message.content?.trim() ?? '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/llm/openai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAI5B,MAAM,OAAO,cAAc;IAIoB;IAH7B,IAAI,GAAG,QAAQ,CAAC;IACf,MAAM,CAAS;IAEhC,YAAY,MAAc,EAAmB,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;QACxD,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;YACzD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YAC7C,WAAW,EAAE,CAAC;SACf,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FileAnalysis } from '../types/analysis.js';
|
|
2
|
+
import type { ClassificationRequest } from '../types/concern.js';
|
|
3
|
+
import type { SkillMatch } from '../types/skill.js';
|
|
4
|
+
export interface CreateClassificationRequestOptions {
|
|
5
|
+
projectRoot: string;
|
|
6
|
+
files: FileAnalysis[];
|
|
7
|
+
matchedSkills: SkillMatch[];
|
|
8
|
+
tokenBudget?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function createClassificationRequest(options: CreateClassificationRequestOptions): ClassificationRequest;
|
|
11
|
+
export declare function buildClassificationPrompt(request: ClassificationRequest): string;
|
|
12
|
+
export declare function sanitizePrompt(prompt: string, projectRoot: string): string;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
const DEFAULT_TOKEN_BUDGET = 2000;
|
|
3
|
+
const AVERAGE_CHARS_PER_TOKEN = 4;
|
|
4
|
+
const REDACTED = '[redacted]';
|
|
5
|
+
export function createClassificationRequest(options) {
|
|
6
|
+
return {
|
|
7
|
+
projectRoot: options.projectRoot,
|
|
8
|
+
skill: createSkillContext(options.matchedSkills),
|
|
9
|
+
files: options.files.map((file) => toFileInput(file, options.projectRoot)),
|
|
10
|
+
tokenBudget: options.tokenBudget ?? DEFAULT_TOKEN_BUDGET
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function buildClassificationPrompt(request) {
|
|
14
|
+
const safeFiles = trimFilesToBudget(request.files, request.tokenBudget, request.skill);
|
|
15
|
+
const payload = {
|
|
16
|
+
task: 'Classify each function by architectural concern. Return only JSON matching the schema.',
|
|
17
|
+
taxonomy: [
|
|
18
|
+
'routing',
|
|
19
|
+
'business_logic',
|
|
20
|
+
'data_access',
|
|
21
|
+
'validation',
|
|
22
|
+
'middleware',
|
|
23
|
+
'ui_component',
|
|
24
|
+
'utility',
|
|
25
|
+
'configuration',
|
|
26
|
+
'test',
|
|
27
|
+
'unclassified'
|
|
28
|
+
],
|
|
29
|
+
output_schema: {
|
|
30
|
+
files: [
|
|
31
|
+
{
|
|
32
|
+
file: 'relative/path.ts',
|
|
33
|
+
functions: [
|
|
34
|
+
{
|
|
35
|
+
name: 'functionName',
|
|
36
|
+
concern: 'routing',
|
|
37
|
+
confidence: 0.9,
|
|
38
|
+
isMisplaced: false,
|
|
39
|
+
reason: 'short non-source explanation'
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
privacy_rules: [
|
|
46
|
+
'Do not ask for full source code.',
|
|
47
|
+
'Use only file paths, imports, function names, parameter counts, line ranges, and skill rules.',
|
|
48
|
+
'If evidence is weak, use unclassified.'
|
|
49
|
+
],
|
|
50
|
+
skill: request.skill,
|
|
51
|
+
files: safeFiles
|
|
52
|
+
};
|
|
53
|
+
return sanitizePrompt(JSON.stringify(payload, null, 2), request.projectRoot);
|
|
54
|
+
}
|
|
55
|
+
export function sanitizePrompt(prompt, projectRoot) {
|
|
56
|
+
const escapedRoot = escapeRegExp(projectRoot);
|
|
57
|
+
return prompt
|
|
58
|
+
.replace(new RegExp(escapedRoot, 'g'), '<project>')
|
|
59
|
+
.replace(/sk-[A-Za-z0-9_-]+/g, REDACTED)
|
|
60
|
+
.replace(/anthropic-[A-Za-z0-9_-]+/g, REDACTED)
|
|
61
|
+
.replace(/(api[_-]?key\s*[=:]\s*)\S+/gi, `$1${REDACTED}`)
|
|
62
|
+
.replace(/(authorization\s*[:=]\s*bearer\s+)\S+/gi, `$1${REDACTED}`);
|
|
63
|
+
}
|
|
64
|
+
function toFileInput(file, projectRoot) {
|
|
65
|
+
return {
|
|
66
|
+
relativePath: toRelativePath(file, projectRoot),
|
|
67
|
+
imports: file.imports.map((item) => ({
|
|
68
|
+
source: sanitizeImportValue(item.source),
|
|
69
|
+
isRelative: item.isRelative,
|
|
70
|
+
isBuiltin: item.isBuiltin,
|
|
71
|
+
specifiers: item.specifiers.map(sanitizeImportValue)
|
|
72
|
+
})),
|
|
73
|
+
functions: file.functions.map((fn) => ({
|
|
74
|
+
name: sanitizeFunctionName(fn.name),
|
|
75
|
+
paramCount: fn.paramCount,
|
|
76
|
+
startLine: fn.startLine,
|
|
77
|
+
endLine: fn.endLine
|
|
78
|
+
}))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function createSkillContext(matches) {
|
|
82
|
+
const primary = matches.find((match) => match.primary);
|
|
83
|
+
if (!primary) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
id: primary.skill.id,
|
|
88
|
+
name: primary.skill.name,
|
|
89
|
+
separationRules: primary.skill.separation.rules
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function trimFilesToBudget(files, tokenBudget, skill) {
|
|
93
|
+
const charBudget = tokenBudget * AVERAGE_CHARS_PER_TOKEN;
|
|
94
|
+
const trimmed = [];
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
const candidate = [...trimmed, file];
|
|
97
|
+
const projected = JSON.stringify({ skill, files: candidate }).length;
|
|
98
|
+
if (projected <= charBudget || trimmed.length === 0) {
|
|
99
|
+
trimmed.push(trimFileFunctions(file, charBudget));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return trimmed;
|
|
103
|
+
}
|
|
104
|
+
function trimFileFunctions(file, charBudget) {
|
|
105
|
+
const functions = [];
|
|
106
|
+
for (const fn of file.functions) {
|
|
107
|
+
const candidate = { ...file, functions: [...functions, fn] };
|
|
108
|
+
if (JSON.stringify(candidate).length <= charBudget || functions.length === 0) {
|
|
109
|
+
functions.push(fn);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
...file,
|
|
114
|
+
functions
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function toRelativePath(file, projectRoot) {
|
|
118
|
+
if (file.relativePath && !path.isAbsolute(file.relativePath)) {
|
|
119
|
+
return file.relativePath;
|
|
120
|
+
}
|
|
121
|
+
return path.relative(projectRoot, file.path);
|
|
122
|
+
}
|
|
123
|
+
function sanitizeImportValue(value) {
|
|
124
|
+
return value.replace(/sk-[A-Za-z0-9_-]+/g, REDACTED).replace(/anthropic-[A-Za-z0-9_-]+/g, REDACTED);
|
|
125
|
+
}
|
|
126
|
+
function sanitizeFunctionName(value) {
|
|
127
|
+
return value || '<anonymous>';
|
|
128
|
+
}
|
|
129
|
+
function escapeRegExp(value) {
|
|
130
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=prompt-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../../src/llm/prompt-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type LLMProviderName = 'claude' | 'openai' | 'ollama' | 'none';
|
|
2
|
+
export type LLMProviderConfigSource = 'environment' | 'config' | 'explicit' | 'fallback';
|
|
3
|
+
export interface LLMProviderConfig {
|
|
4
|
+
provider: LLMProviderName;
|
|
5
|
+
model?: string;
|
|
6
|
+
source: LLMProviderConfigSource;
|
|
7
|
+
isAvailable: boolean;
|
|
8
|
+
warnings: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface LLMProvider {
|
|
11
|
+
name: string;
|
|
12
|
+
analyze(prompt: string): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export interface ProviderResolution {
|
|
15
|
+
config: LLMProviderConfig;
|
|
16
|
+
provider: LLMProvider | null;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConcernClassification, FileClassificationInput } from '../types/concern.js';
|
|
2
|
+
export interface ParsedConcernClassifications {
|
|
3
|
+
classifications: ConcernClassification[];
|
|
4
|
+
warnings: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function parseConcernClassifications(rawResponse: string, inputs: FileClassificationInput[]): ParsedConcernClassifications;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isConcernType } from '../types/concern.js';
|
|
2
|
+
export function parseConcernClassifications(rawResponse, inputs) {
|
|
3
|
+
const warnings = [];
|
|
4
|
+
const parsed = parseJson(rawResponse, warnings);
|
|
5
|
+
if (!parsed) {
|
|
6
|
+
return {
|
|
7
|
+
classifications: inputs.map((input) => createUnclassifiedFile(input, ['Provider returned invalid JSON.'])),
|
|
8
|
+
warnings
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const files = Array.isArray(parsed.files) ? parsed.files : [];
|
|
12
|
+
if (files.length === 0) {
|
|
13
|
+
warnings.push('Provider response did not include any file classifications.');
|
|
14
|
+
}
|
|
15
|
+
const classifications = inputs.map((input) => {
|
|
16
|
+
const rawFile = files.find((item) => item.file === input.relativePath);
|
|
17
|
+
return rawFile ? normalizeFileClassification(input, rawFile, warnings) : createUnclassifiedFile(input, ['No classification returned for file.']);
|
|
18
|
+
});
|
|
19
|
+
return { classifications, warnings };
|
|
20
|
+
}
|
|
21
|
+
function parseJson(rawResponse, warnings) {
|
|
22
|
+
const jsonText = extractJson(rawResponse);
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(jsonText);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
warnings.push('Provider returned invalid JSON.');
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function extractJson(rawResponse) {
|
|
32
|
+
const trimmed = rawResponse.trim();
|
|
33
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(trimmed);
|
|
34
|
+
if (fenced?.[1]) {
|
|
35
|
+
return fenced[1].trim();
|
|
36
|
+
}
|
|
37
|
+
const firstBrace = trimmed.indexOf('{');
|
|
38
|
+
const lastBrace = trimmed.lastIndexOf('}');
|
|
39
|
+
if (firstBrace >= 0 && lastBrace > firstBrace) {
|
|
40
|
+
return trimmed.slice(firstBrace, lastBrace + 1);
|
|
41
|
+
}
|
|
42
|
+
return trimmed;
|
|
43
|
+
}
|
|
44
|
+
function normalizeFileClassification(input, rawFile, warnings) {
|
|
45
|
+
const fileWarnings = [];
|
|
46
|
+
const rawFunctions = Array.isArray(rawFile.functions) ? rawFile.functions : [];
|
|
47
|
+
const functions = input.functions.map((fn) => {
|
|
48
|
+
const rawFunction = rawFunctions.find((item) => item.name === fn.name);
|
|
49
|
+
if (!rawFunction) {
|
|
50
|
+
fileWarnings.push(`No classification returned for ${fn.name}.`);
|
|
51
|
+
return createUnclassifiedFunction(fn.name, 'No classification returned.');
|
|
52
|
+
}
|
|
53
|
+
return normalizeFunctionClassification(fn.name, rawFunction, fileWarnings);
|
|
54
|
+
});
|
|
55
|
+
if (fileWarnings.length > 0) {
|
|
56
|
+
warnings.push(`${input.relativePath}: ${fileWarnings.join(' ')}`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
file: input.relativePath,
|
|
60
|
+
functions,
|
|
61
|
+
dominantConcern: calculateDominantConcern(functions),
|
|
62
|
+
mixedConcerns: calculateMixedConcerns(functions),
|
|
63
|
+
warnings: fileWarnings
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function normalizeFunctionClassification(name, rawFunction, warnings) {
|
|
67
|
+
const concern = normalizeConcern(rawFunction.concern);
|
|
68
|
+
if (concern === 'unclassified' && rawFunction.concern !== 'unclassified') {
|
|
69
|
+
warnings.push(`Unknown concern for ${name}.`);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
name,
|
|
73
|
+
concern,
|
|
74
|
+
confidence: normalizeConfidence(rawFunction.confidence),
|
|
75
|
+
isMisplaced: rawFunction.isMisplaced === true,
|
|
76
|
+
reason: typeof rawFunction.reason === 'string' ? rawFunction.reason : undefined
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function createUnclassifiedFile(input, warnings) {
|
|
80
|
+
return {
|
|
81
|
+
file: input.relativePath,
|
|
82
|
+
functions: input.functions.map((fn) => createUnclassifiedFunction(fn.name, warnings[0])),
|
|
83
|
+
dominantConcern: 'unclassified',
|
|
84
|
+
mixedConcerns: false,
|
|
85
|
+
warnings
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createUnclassifiedFunction(name, reason) {
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
concern: 'unclassified',
|
|
92
|
+
confidence: 0,
|
|
93
|
+
isMisplaced: false,
|
|
94
|
+
reason
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function normalizeConcern(value) {
|
|
98
|
+
if (typeof value !== 'string') {
|
|
99
|
+
return 'unclassified';
|
|
100
|
+
}
|
|
101
|
+
return isConcernType(value) ? value : 'unclassified';
|
|
102
|
+
}
|
|
103
|
+
function normalizeConfidence(value) {
|
|
104
|
+
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
return Math.max(0, Math.min(1, value));
|
|
108
|
+
}
|
|
109
|
+
function calculateDominantConcern(functions) {
|
|
110
|
+
const counts = new Map();
|
|
111
|
+
for (const fn of functions) {
|
|
112
|
+
counts.set(fn.concern, (counts.get(fn.concern) ?? 0) + 1);
|
|
113
|
+
}
|
|
114
|
+
let dominant = 'unclassified';
|
|
115
|
+
let max = 0;
|
|
116
|
+
for (const [concern, count] of counts.entries()) {
|
|
117
|
+
if (concern !== 'unclassified' && count > max) {
|
|
118
|
+
dominant = concern;
|
|
119
|
+
max = count;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return dominant;
|
|
123
|
+
}
|
|
124
|
+
function calculateMixedConcerns(functions) {
|
|
125
|
+
const concerns = new Set(functions.map((fn) => fn.concern).filter((concern) => concern !== 'unclassified'));
|
|
126
|
+
return concerns.size >= 3;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=response-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-parser.js","sourceRoot":"","sources":["../../src/llm/response-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ScanResult } from '../types/analysis.js';
|
|
2
|
+
import type { ReportIssue } from '../types/issue.js';
|
|
3
|
+
import type { PlanGenerationContext, RefactorPlan } from '../types/plan.js';
|
|
4
|
+
import type { SkillMatch } from '../types/skill.js';
|
|
5
|
+
export declare function generateRefactorPlan(context: PlanGenerationContext): RefactorPlan;
|
|
6
|
+
export declare function primarySkillFrom(scan: ScanResult): SkillMatch | null;
|
|
7
|
+
export declare function issuesBySeverity(scan: ScanResult): ReportIssue[];
|