agent-rules-init 0.3.0 → 0.4.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/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/cli.d.ts +23 -4
- package/dist/cli.js +147 -38
- package/dist/core/canonical-commands.d.ts +4 -0
- package/dist/core/canonical-commands.js +169 -0
- package/dist/core/config.d.ts +25 -0
- package/dist/core/config.js +125 -0
- package/dist/core/i18n.d.ts +8 -5
- package/dist/core/i18n.js +61 -30
- package/dist/core/llm-bridge.d.ts +3 -0
- package/dist/core/llm-bridge.js +52 -0
- package/dist/core/project-unit-output.d.ts +13 -0
- package/dist/core/project-unit-output.js +25 -0
- package/dist/core/project-units.d.ts +16 -0
- package/dist/core/project-units.js +95 -0
- package/dist/core/repo-facts.d.ts +12 -2
- package/dist/core/repo-facts.js +233 -11
- package/dist/core/scanner.js +128 -25
- package/dist/core/templates.js +99 -26
- package/dist/core/types.d.ts +54 -3
- package/dist/core/writer.js +6 -6
- package/dist/packs/cpp.js +3 -3
- package/dist/packs/csharp.js +3 -3
- package/dist/packs/dart.js +4 -4
- package/dist/packs/elixir.js +2 -2
- package/dist/packs/go.js +2 -2
- package/dist/packs/java.js +57 -11
- package/dist/packs/js-ts.js +126 -23
- package/dist/packs/kotlin.js +29 -9
- package/dist/packs/php.js +4 -4
- package/dist/packs/python.js +81 -16
- package/dist/packs/r.js +4 -4
- package/dist/packs/ruby.js +6 -6
- package/dist/packs/rust.js +2 -2
- package/dist/packs/scala.js +3 -3
- package/dist/packs/swift.js +2 -2
- package/package.json +5 -3
package/dist/core/templates.js
CHANGED
|
@@ -1,44 +1,82 @@
|
|
|
1
1
|
import { UI } from "./i18n.js";
|
|
2
|
-
|
|
2
|
+
import { SOURCE_FILES } from "./canonical-commands.js";
|
|
3
|
+
function renderSection(entries, lang, options = {}) {
|
|
3
4
|
const ui = UI[lang];
|
|
5
|
+
const { summaries = true } = options;
|
|
4
6
|
return entries
|
|
5
7
|
.map(({ detection, ruleSet }) => {
|
|
6
|
-
const
|
|
8
|
+
const conventionItems = options.operationalConventions === false
|
|
9
|
+
? ruleSet.conventions.filter((item) => !/^(?:Run the tests|Run the repository|Ejecuta los tests|Ejecuta la suite)/i.test(item))
|
|
10
|
+
: ruleSet.conventions;
|
|
11
|
+
const conventions = conventionItems.map((c) => `- ${c}`).join("\n");
|
|
7
12
|
const architecture = ruleSet.architectureNotes.map((a) => `- ${a}`).join("\n");
|
|
8
|
-
|
|
13
|
+
const parts = [
|
|
9
14
|
`## ${detection.language} (${detection.packId})`,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"",
|
|
13
|
-
|
|
14
|
-
conventions
|
|
15
|
-
|
|
16
|
-
`### ${ui.sections.architecture}`,
|
|
17
|
-
|
|
18
|
-
].join("\n");
|
|
15
|
+
];
|
|
16
|
+
if (summaries)
|
|
17
|
+
parts.push("", ruleSet.summary);
|
|
18
|
+
if (options.conventions !== false && conventions)
|
|
19
|
+
parts.push("", `### ${ui.sections.conventions}`, conventions);
|
|
20
|
+
if (options.architecture !== false && architecture)
|
|
21
|
+
parts.push("", `### ${ui.sections.architecture}`, architecture);
|
|
22
|
+
return parts.join("\n");
|
|
19
23
|
})
|
|
20
24
|
.join("\n\n");
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
function evidenceLabel(lang) {
|
|
27
|
+
return lang === "es" ? "evidencia" : "evidence";
|
|
28
|
+
}
|
|
29
|
+
function renderEvidenceSection(title, facts, lang) {
|
|
30
|
+
const high = facts.filter((fact) => fact.confidence === "high");
|
|
31
|
+
if (high.length === 0)
|
|
32
|
+
return "";
|
|
33
|
+
const lines = high.map((fact) => `- ${fact.statement} (${evidenceLabel(lang)}: ${fact.evidence.map((item) => `\`${item}\``).join(", ")})`);
|
|
34
|
+
return [`## ${title}`, "", ...lines].join("\n");
|
|
35
|
+
}
|
|
36
|
+
function architectureFactsTitle(lang) {
|
|
37
|
+
return lang === "es" ? "Arquitectura observada" : "Observed architecture";
|
|
38
|
+
}
|
|
39
|
+
function localConventionsTitle(lang) {
|
|
40
|
+
return lang === "es" ? "Convenciones locales verificadas" : "Verified local conventions";
|
|
41
|
+
}
|
|
42
|
+
function renderCanonical(facts, lang) {
|
|
43
|
+
const commands = facts.canonical.filter((command) => command.confidence === "high");
|
|
44
|
+
if (commands.length === 0)
|
|
45
|
+
return "";
|
|
46
|
+
return [
|
|
47
|
+
`## ${UI[lang].sections.canonical}`,
|
|
48
|
+
"",
|
|
49
|
+
...commands.map((command) => `- ${command.kind}: \`${command.command}\` (${command.source})`),
|
|
50
|
+
].join("\n");
|
|
51
|
+
}
|
|
29
52
|
export function renderRepoFacts(facts, lang) {
|
|
30
53
|
const ui = UI[lang];
|
|
31
54
|
const sections = [];
|
|
55
|
+
const canonical = facts.canonical.filter((c) => c.confidence === "high");
|
|
56
|
+
if (canonical.length > 0) {
|
|
57
|
+
const lines = canonical.map((c) => `- ${c.kind}: \`${c.command}\` (${c.source})`);
|
|
58
|
+
sections.push([`## ${ui.sections.canonical}`, "", ...lines].join("\n"));
|
|
59
|
+
}
|
|
32
60
|
if (facts.commands.length > 0) {
|
|
33
|
-
const lines = facts.commands.map((c) =>
|
|
34
|
-
|
|
35
|
-
|
|
61
|
+
const lines = facts.commands.map((c) => {
|
|
62
|
+
const sourceFile = c.manifestPath ?? SOURCE_FILES[c.source];
|
|
63
|
+
return c.detail && c.detail !== c.invocation
|
|
64
|
+
? `- \`${c.invocation}\` → \`${c.detail}\` (${sourceFile})`
|
|
65
|
+
: `- \`${c.invocation}\` (${sourceFile})`;
|
|
66
|
+
});
|
|
36
67
|
for (const o of facts.omittedCommands)
|
|
37
68
|
lines.push(`- ${ui.andMore(o.count, SOURCE_FILES[o.source])}`);
|
|
38
69
|
sections.push([`## ${ui.sections.commands}`, "", ...lines].join("\n"));
|
|
39
70
|
}
|
|
40
|
-
if (facts.structure.length > 0) {
|
|
71
|
+
if (facts.structure.length > 0 || facts.testDirs.length > 0 || facts.entrypoints.length > 0) {
|
|
41
72
|
const lines = facts.structure.map((d) => (d.note ? `- \`${d.dir}\` — ${d.note}` : `- \`${d.dir}\``));
|
|
73
|
+
for (const dir of facts.testDirs) {
|
|
74
|
+
if (!facts.structure.some((d) => d.dir === dir))
|
|
75
|
+
lines.push(`- \`${dir}\` — ${ui.testDirNote}`);
|
|
76
|
+
}
|
|
77
|
+
for (const entry of facts.entrypoints) {
|
|
78
|
+
lines.push(`- ${ui.entrypointNote}: \`${entry.target}\` (${entry.source} "${entry.label}")`);
|
|
79
|
+
}
|
|
42
80
|
sections.push([`## ${ui.sections.structure}`, "", ...lines].join("\n"));
|
|
43
81
|
}
|
|
44
82
|
if (facts.ciCommands.length > 0) {
|
|
@@ -47,6 +85,12 @@ export function renderRepoFacts(facts, lang) {
|
|
|
47
85
|
lines.push(`- ${ui.andMore(facts.omittedCiCount)}`);
|
|
48
86
|
sections.push([`## ${ui.sections.ci}`, "", ...lines].join("\n"));
|
|
49
87
|
}
|
|
88
|
+
const architecture = renderEvidenceSection(architectureFactsTitle(lang), facts.architectureFacts ?? [], lang);
|
|
89
|
+
if (architecture)
|
|
90
|
+
sections.push(architecture);
|
|
91
|
+
const conventions = renderEvidenceSection(localConventionsTitle(lang), facts.conventionFacts ?? [], lang);
|
|
92
|
+
if (conventions)
|
|
93
|
+
sections.push(conventions);
|
|
50
94
|
return sections.join("\n\n");
|
|
51
95
|
}
|
|
52
96
|
function renderDocument(title, entries, facts, lang) {
|
|
@@ -56,7 +100,7 @@ function renderDocument(title, entries, facts, lang) {
|
|
|
56
100
|
"",
|
|
57
101
|
UI[lang].generatedHeader,
|
|
58
102
|
"",
|
|
59
|
-
renderSection(entries, lang),
|
|
103
|
+
renderSection(entries, lang, { architecture: !(facts?.architectureFacts?.length) }),
|
|
60
104
|
...(factsBlock ? ["", factsBlock] : []),
|
|
61
105
|
].join("\n");
|
|
62
106
|
}
|
|
@@ -64,10 +108,39 @@ export function renderClaudeMd(entries, facts, lang) {
|
|
|
64
108
|
return renderDocument("# CLAUDE.md", entries, facts, lang);
|
|
65
109
|
}
|
|
66
110
|
export function renderAgentsMd(entries, facts, lang) {
|
|
67
|
-
|
|
111
|
+
const intro = lang === "es"
|
|
112
|
+
? "Reglas operativas para modificar este repositorio. Respeta el alcance y valida los cambios con los comandos indicados."
|
|
113
|
+
: "Operational rules for modifying this repository. Respect scope and validate changes with the commands below.";
|
|
114
|
+
const blocks = [
|
|
115
|
+
"# AGENTS.md", "", UI[lang].generatedHeader, "", intro, "",
|
|
116
|
+
renderSection(entries, lang, { architecture: !(facts?.architectureFacts?.length) }),
|
|
117
|
+
];
|
|
118
|
+
if (facts) {
|
|
119
|
+
const canonical = renderCanonical(facts, lang);
|
|
120
|
+
const architecture = renderEvidenceSection(architectureFactsTitle(lang), facts.architectureFacts ?? [], lang);
|
|
121
|
+
const conventions = renderEvidenceSection(localConventionsTitle(lang), facts.conventionFacts ?? [], lang);
|
|
122
|
+
for (const block of [canonical, architecture, conventions])
|
|
123
|
+
if (block)
|
|
124
|
+
blocks.push("", block);
|
|
125
|
+
}
|
|
126
|
+
return blocks.join("\n");
|
|
68
127
|
}
|
|
69
128
|
export function renderCopilotInstructions(entries, facts, lang) {
|
|
70
|
-
|
|
129
|
+
const intro = lang === "es"
|
|
130
|
+
? "Aplica estas convenciones al completar y modificar código. Omite tareas operativas de terminal salvo que sean necesarias para el cambio."
|
|
131
|
+
: "Apply these conventions when completing and modifying code. Omit terminal operations unless the change requires them.";
|
|
132
|
+
const blocks = [
|
|
133
|
+
"# Copilot Instructions", "", UI[lang].generatedHeader, "", intro, "",
|
|
134
|
+
renderSection(entries, lang, { architecture: false, operationalConventions: false }),
|
|
135
|
+
];
|
|
136
|
+
if (facts) {
|
|
137
|
+
const conventions = renderEvidenceSection(localConventionsTitle(lang), facts.conventionFacts ?? [], lang);
|
|
138
|
+
const architecture = renderEvidenceSection(architectureFactsTitle(lang), facts.architectureFacts ?? [], lang);
|
|
139
|
+
for (const block of [conventions, architecture])
|
|
140
|
+
if (block)
|
|
141
|
+
blocks.push("", block);
|
|
142
|
+
}
|
|
143
|
+
return blocks.join("\n");
|
|
71
144
|
}
|
|
72
145
|
export function renderPromptFiles(packId, templates) {
|
|
73
146
|
return templates.flatMap((template) => [
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import type { Lang } from "./i18n.js";
|
|
2
|
+
export type JsPackageManager = "npm" | "pnpm" | "yarn" | "bun";
|
|
2
3
|
export interface PackageJsonManifest {
|
|
3
4
|
name?: string;
|
|
5
|
+
main?: string;
|
|
4
6
|
dependencies: Record<string, string>;
|
|
5
7
|
devDependencies: Record<string, string>;
|
|
6
8
|
scripts: Record<string, string>;
|
|
7
9
|
moduleType: "module" | "commonjs";
|
|
10
|
+
/** Gestor aplicable al manifiesto, declarado en packageManager o inferido por el lock más cercano. */
|
|
11
|
+
packageManager?: JsPackageManager;
|
|
12
|
+
}
|
|
13
|
+
export interface LocatedPackageJsonManifest extends PackageJsonManifest {
|
|
14
|
+
path: string;
|
|
8
15
|
}
|
|
9
16
|
export interface ComposerJsonManifest {
|
|
10
17
|
require: Record<string, string>;
|
|
@@ -17,6 +24,7 @@ export interface RepoSignals {
|
|
|
17
24
|
hasFile: (relativePath: string) => boolean;
|
|
18
25
|
hasDir: (relativeDir: string) => boolean;
|
|
19
26
|
packageJson?: PackageJsonManifest;
|
|
27
|
+
packageJsons?: LocatedPackageJsonManifest[];
|
|
20
28
|
pyprojectToml?: string;
|
|
21
29
|
requirementsTxt?: string;
|
|
22
30
|
environmentYml?: string;
|
|
@@ -40,6 +48,11 @@ export interface RepoSignals {
|
|
|
40
48
|
path: string;
|
|
41
49
|
content: string;
|
|
42
50
|
}[];
|
|
51
|
+
/** Archivos locales de guía/configuración seleccionados de forma conservadora. */
|
|
52
|
+
guidanceFiles?: {
|
|
53
|
+
path: string;
|
|
54
|
+
content: string;
|
|
55
|
+
}[];
|
|
43
56
|
}
|
|
44
57
|
export type Confidence = "high" | "low";
|
|
45
58
|
export interface DetectionField<T> {
|
|
@@ -53,6 +66,8 @@ export interface DetectionResult {
|
|
|
53
66
|
packageManager?: DetectionField<string>;
|
|
54
67
|
testRunner?: DetectionField<string>;
|
|
55
68
|
linter?: DetectionField<string>;
|
|
69
|
+
/** Framework implementado por el propio repositorio; no implica una dependencia. */
|
|
70
|
+
frameworkSource?: string;
|
|
56
71
|
usesTypeScript?: boolean;
|
|
57
72
|
moduleFormat?: "module" | "commonjs";
|
|
58
73
|
}
|
|
@@ -66,11 +81,12 @@ export interface PromptTemplate {
|
|
|
66
81
|
title: string;
|
|
67
82
|
body: string;
|
|
68
83
|
}
|
|
69
|
-
export type CommandSource =
|
|
84
|
+
export type CommandSource = JsPackageManager | "composer" | "make" | "mix" | "tox";
|
|
70
85
|
export interface CommandEntry {
|
|
71
86
|
source: CommandSource;
|
|
72
87
|
invocation: string;
|
|
73
88
|
detail?: string;
|
|
89
|
+
manifestPath?: string;
|
|
74
90
|
}
|
|
75
91
|
export interface DirEntry {
|
|
76
92
|
dir: string;
|
|
@@ -80,6 +96,27 @@ export interface CiCommand {
|
|
|
80
96
|
command: string;
|
|
81
97
|
workflow: string;
|
|
82
98
|
}
|
|
99
|
+
export interface CanonicalCommand {
|
|
100
|
+
kind: "test" | "lint" | "build" | "format" | "typecheck";
|
|
101
|
+
command: string;
|
|
102
|
+
/** Archivo o señal del que procede el comando, p. ej. `package.json`, `ci: ci.yml`, `mvnw`. */
|
|
103
|
+
source: string;
|
|
104
|
+
confidence: Confidence;
|
|
105
|
+
/** "." para la raíz del repo; ruta del workspace para unidades anidadas. */
|
|
106
|
+
scope: string;
|
|
107
|
+
}
|
|
108
|
+
export interface EvidenceFact {
|
|
109
|
+
statement: string;
|
|
110
|
+
evidence: string[];
|
|
111
|
+
scope: string;
|
|
112
|
+
confidence: Confidence;
|
|
113
|
+
}
|
|
114
|
+
export interface ArchitectureFact extends EvidenceFact {
|
|
115
|
+
kind: "entrypoint" | "tests" | "layers" | "workspace" | "source-layout";
|
|
116
|
+
}
|
|
117
|
+
export interface ConventionFact extends EvidenceFact {
|
|
118
|
+
kind: "formatting" | "typescript" | "python-style" | "contributing";
|
|
119
|
+
}
|
|
83
120
|
export interface RepoFacts {
|
|
84
121
|
commands: CommandEntry[];
|
|
85
122
|
omittedCommands: {
|
|
@@ -89,10 +126,24 @@ export interface RepoFacts {
|
|
|
89
126
|
structure: DirEntry[];
|
|
90
127
|
ciCommands: CiCommand[];
|
|
91
128
|
omittedCiCount: number;
|
|
129
|
+
canonical: CanonicalCommand[];
|
|
130
|
+
testDirs: string[];
|
|
131
|
+
entrypoints: {
|
|
132
|
+
label: string;
|
|
133
|
+
target: string;
|
|
134
|
+
source: string;
|
|
135
|
+
}[];
|
|
136
|
+
architectureFacts: ArchitectureFact[];
|
|
137
|
+
conventionFacts: ConventionFact[];
|
|
138
|
+
}
|
|
139
|
+
export interface PackContext {
|
|
140
|
+
facts: RepoFacts;
|
|
141
|
+
/** Señales del mismo alcance que facts; permite evitar canónicos de otro stack. */
|
|
142
|
+
signals?: RepoSignals;
|
|
92
143
|
}
|
|
93
144
|
export interface Pack {
|
|
94
145
|
id: string;
|
|
95
146
|
detect(signals: RepoSignals): DetectionResult | null;
|
|
96
|
-
rules(detection: DetectionResult, lang: Lang): RuleSet;
|
|
97
|
-
promptTemplates(detection: DetectionResult, lang: Lang): PromptTemplate[];
|
|
147
|
+
rules(detection: DetectionResult, lang: Lang, ctx?: PackContext): RuleSet;
|
|
148
|
+
promptTemplates(detection: DetectionResult, lang: Lang, ctx?: PackContext): PromptTemplate[];
|
|
98
149
|
}
|
package/dist/core/writer.js
CHANGED
|
@@ -4,16 +4,16 @@ export function writeGeneratedFiles(rootPath, files) {
|
|
|
4
4
|
return files.map(({ path: relativePath, content }) => {
|
|
5
5
|
const absolutePath = path.join(rootPath, relativePath);
|
|
6
6
|
try {
|
|
7
|
-
// An already-existing file is the expected outcome on a re-run (the tool's
|
|
8
|
-
// no-overwrite guarantee), not a failure — report it as skipped, exit 0.
|
|
9
|
-
if (fs.existsSync(absolutePath)) {
|
|
10
|
-
return { path: relativePath, status: "skipped" };
|
|
11
|
-
}
|
|
12
7
|
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
|
|
13
|
-
|
|
8
|
+
// `wx` makes the no-overwrite guarantee atomic: even if another process creates
|
|
9
|
+
// the file between directory creation and this call, Node returns EEXIST.
|
|
10
|
+
fs.writeFileSync(absolutePath, content, { flag: "wx" });
|
|
14
11
|
return { path: relativePath, status: "written" };
|
|
15
12
|
}
|
|
16
13
|
catch (err) {
|
|
14
|
+
if (err.code === "EEXIST") {
|
|
15
|
+
return { path: relativePath, status: "skipped" };
|
|
16
|
+
}
|
|
17
17
|
return { path: relativePath, status: "error", error: err.message };
|
|
18
18
|
}
|
|
19
19
|
});
|
package/dist/packs/cpp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
2
|
const FRAMEWORKS = [
|
|
3
3
|
["find_package(qt", "qt"],
|
|
4
4
|
["find_package(boost", "boost"],
|
|
@@ -79,8 +79,8 @@ function rules(detection, lang) {
|
|
|
79
79
|
}
|
|
80
80
|
function promptTemplates(detection, lang) {
|
|
81
81
|
const t = TEXTS[lang];
|
|
82
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
83
|
-
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner
|
|
82
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
83
|
+
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : undefined;
|
|
84
84
|
return [
|
|
85
85
|
{ id: "review", title: "Code Review (C/C++)", body: reviewBody(lang, t.reviewFocus, framework) },
|
|
86
86
|
{ id: "refactor", title: "Refactor (C/C++)", body: refactorBody(lang) },
|
package/dist/packs/csharp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
2
|
function detect(signals) {
|
|
3
3
|
const source = signals.csproj;
|
|
4
4
|
if (!source)
|
|
@@ -53,8 +53,8 @@ function rules(detection, lang) {
|
|
|
53
53
|
}
|
|
54
54
|
function promptTemplates(detection, lang) {
|
|
55
55
|
const t = TEXTS[lang];
|
|
56
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
57
|
-
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner
|
|
56
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
57
|
+
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : undefined;
|
|
58
58
|
return [
|
|
59
59
|
{ id: "review", title: "Code Review (C#/.NET)", body: reviewBody(lang, t.reviewFocus, framework) },
|
|
60
60
|
{ id: "refactor", title: "Refactor (C#/.NET)", body: refactorBody(lang) },
|
package/dist/packs/dart.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
2
|
function detect(signals) {
|
|
3
3
|
const source = signals.pubspecYaml;
|
|
4
4
|
if (!source)
|
|
@@ -44,13 +44,13 @@ function rules(detection, lang) {
|
|
|
44
44
|
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : undefined;
|
|
45
45
|
return {
|
|
46
46
|
summary: summarySentence(lang, "Dart", framework, "pub"),
|
|
47
|
-
conventions: [t.style, runTestsConvention(lang, runner
|
|
47
|
+
conventions: [t.style, runTestsConvention(lang, runner), t.deps],
|
|
48
48
|
architectureNotes: [framework === "flutter" ? t.archFlutter : t.archPlain, t.immutability],
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
function promptTemplates(detection, lang) {
|
|
52
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
53
|
-
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner
|
|
52
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
53
|
+
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : undefined;
|
|
54
54
|
return [
|
|
55
55
|
{ id: "review", title: "Code Review (Dart)", body: reviewBody(lang, "", framework) },
|
|
56
56
|
{ id: "refactor", title: "Refactor (Dart)", body: refactorBody(lang) },
|
package/dist/packs/elixir.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
2
|
function detect(signals) {
|
|
3
3
|
const source = signals.mixExs;
|
|
4
4
|
if (!source)
|
|
@@ -50,7 +50,7 @@ function rules(detection, lang) {
|
|
|
50
50
|
}
|
|
51
51
|
function promptTemplates(detection, lang) {
|
|
52
52
|
const t = TEXTS[lang];
|
|
53
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
53
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
54
54
|
return [
|
|
55
55
|
{ id: "review", title: "Code Review (Elixir)", body: reviewBody(lang, t.reviewFocus, framework) },
|
|
56
56
|
{ id: "refactor", title: "Refactor (Elixir)", body: refactorBody(lang) },
|
package/dist/packs/go.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
2
|
const FRAMEWORKS = [
|
|
3
3
|
["gin-gonic/gin", "gin"],
|
|
4
4
|
["labstack/echo", "echo"],
|
|
@@ -68,7 +68,7 @@ function rules(detection, lang) {
|
|
|
68
68
|
}
|
|
69
69
|
function promptTemplates(detection, lang) {
|
|
70
70
|
const t = TEXTS[lang];
|
|
71
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
71
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
72
72
|
return [
|
|
73
73
|
{ id: "review", title: "Code Review (Go)", body: reviewBody(lang, t.reviewFocus, framework) },
|
|
74
74
|
{ id: "refactor", title: "Refactor (Go)", body: refactorBody(lang) },
|
package/dist/packs/java.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody,
|
|
1
|
+
import { refactorBody, reviewBody, runTestsConvention, summarySentence, testingBody, } from "../core/i18n.js";
|
|
2
|
+
import { canonicalOf } from "../core/canonical-commands.js";
|
|
3
|
+
const SPRING_RISK = {
|
|
4
|
+
es: "Presta especial atención a los límites de transacción (@Transactional), la inyección de dependencias y la separación controller/service/repository.",
|
|
5
|
+
en: "Pay special attention to transaction boundaries (@Transactional), dependency injection and the controller/service/repository separation.",
|
|
6
|
+
};
|
|
2
7
|
function detect(signals) {
|
|
3
8
|
const source = signals.pomXml ?? signals.buildGradle;
|
|
4
9
|
if (!source)
|
|
@@ -9,14 +14,19 @@ function detect(signals) {
|
|
|
9
14
|
// (`alias(libs.plugins.kotlin.android)`) rather than the literal `kotlin("jvm")` or
|
|
10
15
|
// `org.jetbrains.kotlin` plugin id, so a plain word-boundary check on "kotlin" is
|
|
11
16
|
// more robust than trying to match every DSL style.
|
|
12
|
-
if (/\bkotlin\b/i.test(
|
|
17
|
+
if ((signals.buildGradle && /\bkotlin\b/i.test(signals.buildGradle)) ||
|
|
18
|
+
(signals.pomXml && /\bkotlin\b/i.test(signals.pomXml)))
|
|
13
19
|
return null;
|
|
14
20
|
const framework = /spring/i.test(source)
|
|
15
21
|
? { value: "spring", confidence: "high" }
|
|
16
22
|
: { value: "none", confidence: "low" };
|
|
17
23
|
const packageManager = signals.pomXml
|
|
18
|
-
?
|
|
19
|
-
|
|
24
|
+
? signals.hasFile("mvnw") || signals.hasFile("mvnw.cmd")
|
|
25
|
+
? { value: "maven wrapper", confidence: "high" }
|
|
26
|
+
: { value: "maven", confidence: "high" }
|
|
27
|
+
: signals.hasFile("gradlew") || signals.hasFile("gradlew.bat")
|
|
28
|
+
? { value: "gradle wrapper", confidence: "high" }
|
|
29
|
+
: { value: "gradle", confidence: "high" };
|
|
20
30
|
const testRunner = /junit/i.test(source)
|
|
21
31
|
? { value: "junit", confidence: "high" }
|
|
22
32
|
: { value: "unknown", confidence: "low" };
|
|
@@ -42,24 +52,60 @@ const TEXTS = {
|
|
|
42
52
|
reviewFocus: "null-safety",
|
|
43
53
|
},
|
|
44
54
|
};
|
|
45
|
-
function rules(detection, lang) {
|
|
55
|
+
function rules(detection, lang, ctx) {
|
|
46
56
|
const t = TEXTS[lang];
|
|
47
57
|
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
48
|
-
const
|
|
58
|
+
const wrapperCmd = detection.packageManager?.value === "maven wrapper"
|
|
59
|
+
? "./mvnw test"
|
|
60
|
+
: detection.packageManager?.value === "maven"
|
|
61
|
+
? "mvn test"
|
|
62
|
+
: detection.packageManager?.value === "gradle wrapper"
|
|
63
|
+
? "./gradlew test"
|
|
64
|
+
: "gradle test";
|
|
65
|
+
const testCmd = canonicalOf(ctx, "test", "java")?.command ?? wrapperCmd;
|
|
49
66
|
return {
|
|
50
67
|
summary: summarySentence(lang, "Java", framework, detection.packageManager?.value),
|
|
51
68
|
conventions: [t.naming, runTestsConvention(lang, testCmd), t.deps],
|
|
52
69
|
architectureNotes: t.arch,
|
|
53
70
|
};
|
|
54
71
|
}
|
|
55
|
-
function promptTemplates(detection, lang) {
|
|
72
|
+
function promptTemplates(detection, lang, ctx) {
|
|
56
73
|
const t = TEXTS[lang];
|
|
57
|
-
const framework = detection.framework?.value !== "none" ? detection.framework
|
|
58
|
-
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner
|
|
74
|
+
const framework = detection.framework?.value !== "none" ? detection.framework?.value : undefined;
|
|
75
|
+
const runner = detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : undefined;
|
|
76
|
+
const test = canonicalOf(ctx, "test", "java");
|
|
77
|
+
const build = canonicalOf(ctx, "build", "java");
|
|
78
|
+
const testDirs = ctx?.facts.testDirs ?? [];
|
|
79
|
+
const es = lang === "es";
|
|
80
|
+
const reviewParts = [];
|
|
81
|
+
reviewParts.push(es
|
|
82
|
+
? `Revisa el diff actual contra las convenciones Java de este repositorio${framework ? ` (${framework})` : ""}.`
|
|
83
|
+
: `Review the current diff against this repository's Java conventions${framework ? ` (${framework})` : ""}.`);
|
|
84
|
+
if (test) {
|
|
85
|
+
reviewParts.push(es ? `Ejecuta \`${test.command}\` antes de dar por buena la revisión.` : `Run \`${test.command}\` before approving the review.`);
|
|
86
|
+
}
|
|
87
|
+
if (build && build.command !== test?.command) {
|
|
88
|
+
reviewParts.push(es ? `CI también ejecuta \`${build.command}\`.` : `CI also runs \`${build.command}\`.`);
|
|
89
|
+
}
|
|
90
|
+
if (framework === "spring")
|
|
91
|
+
reviewParts.push(SPRING_RISK[lang]);
|
|
92
|
+
reviewParts.push(es ? `Busca también bugs: ${t.reviewFocus}.` : `Also look for bugs: ${t.reviewFocus}.`);
|
|
93
|
+
if (testDirs.length > 0) {
|
|
94
|
+
const dirs = testDirs.map((d) => `\`${d}\``).join(", ");
|
|
95
|
+
reviewParts.push(es ? `Los tests viven en ${dirs}.` : `Tests live under ${dirs}.`);
|
|
96
|
+
}
|
|
97
|
+
reviewParts.push(es ? "Señala solo hallazgos concretos con archivo y línea." : "Report only concrete findings with file and line references.");
|
|
98
|
+
const testingParts = [testingBody(lang, runner)];
|
|
99
|
+
if (test)
|
|
100
|
+
testingParts.push(es ? `Verifica la suite con \`${test.command}\` antes de terminar.` : `Verify the suite with \`${test.command}\` before finishing.`);
|
|
101
|
+
if (testDirs.length > 0) {
|
|
102
|
+
const dirs = testDirs.map((d) => `\`${d}\``).join(", ");
|
|
103
|
+
testingParts.push(es ? `Coloca los tests nuevos en ${dirs}.` : `Place new tests under ${dirs}.`);
|
|
104
|
+
}
|
|
59
105
|
return [
|
|
60
|
-
{ id: "review", title: "Code Review (Java)", body: reviewBody(lang, t.reviewFocus, framework) },
|
|
106
|
+
{ id: "review", title: "Code Review (Java)", body: ctx ? reviewParts.join(" ") : reviewBody(lang, t.reviewFocus, framework) },
|
|
61
107
|
{ id: "refactor", title: "Refactor (Java)", body: refactorBody(lang) },
|
|
62
|
-
{ id: "testing", title: "Testing (Java)", body: testingBody(lang, runner) },
|
|
108
|
+
{ id: "testing", title: "Testing (Java)", body: ctx ? testingParts.join(" ") : testingBody(lang, runner) },
|
|
63
109
|
];
|
|
64
110
|
}
|
|
65
111
|
export const javaPack = { id: "java", detect, rules, promptTemplates };
|