agent-rules-init 0.1.3 → 0.2.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/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./cli.js";
3
+ main();
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { type WriteResult } from "./core/writer.js";
3
2
  import { type PromptFn } from "./core/prompt-engine.js";
4
3
  import { type ExecFn } from "./core/llm-bridge.js";
@@ -8,3 +7,4 @@ export interface RunCliOptions {
8
7
  skipLlm?: boolean;
9
8
  }
10
9
  export declare function runCli(rootPath: string, options?: RunCliOptions): Promise<WriteResult[]>;
10
+ export declare function main(): Promise<void>;
package/dist/cli.js CHANGED
@@ -1,16 +1,41 @@
1
- #!/usr/bin/env node
2
1
  import * as clack from "@clack/prompts";
3
- import { pathToFileURL } from "node:url";
4
2
  import { scanRepo } from "./core/scanner.js";
5
3
  import { writeGeneratedFiles } from "./core/writer.js";
6
4
  import { renderClaudeMd, renderAgentsMd, renderCopilotInstructions, renderPromptFiles, } from "./core/templates.js";
7
5
  import { collectLowConfidenceQuestions, askQuestions, applyAnswers, defaultPromptFn, hasInteractiveTty, } from "./core/prompt-engine.js";
8
6
  import { detectAvailableAssistants, polishWithAssistant, defaultExecFn } from "./core/llm-bridge.js";
9
- import { jsTsPack } from "agent-rules-pack-js-ts";
10
- import { pythonPack } from "agent-rules-pack-python";
11
- import { javaPack } from "agent-rules-pack-java";
12
- import { phpPack } from "agent-rules-pack-php";
13
- const ALL_PACKS = [jsTsPack, pythonPack, javaPack, phpPack];
7
+ import { jsTsPack } from "./packs/js-ts.js";
8
+ import { pythonPack } from "./packs/python.js";
9
+ import { javaPack } from "./packs/java.js";
10
+ import { phpPack } from "./packs/php.js";
11
+ import { rubyPack } from "./packs/ruby.js";
12
+ import { goPack } from "./packs/go.js";
13
+ import { rustPack } from "./packs/rust.js";
14
+ import { csharpPack } from "./packs/csharp.js";
15
+ import { kotlinPack } from "./packs/kotlin.js";
16
+ import { swiftPack } from "./packs/swift.js";
17
+ import { dartPack } from "./packs/dart.js";
18
+ import { cppPack } from "./packs/cpp.js";
19
+ import { elixirPack } from "./packs/elixir.js";
20
+ import { scalaPack } from "./packs/scala.js";
21
+ import { rPack } from "./packs/r.js";
22
+ const ALL_PACKS = [
23
+ jsTsPack,
24
+ pythonPack,
25
+ javaPack,
26
+ phpPack,
27
+ rubyPack,
28
+ goPack,
29
+ rustPack,
30
+ csharpPack,
31
+ kotlinPack,
32
+ swiftPack,
33
+ dartPack,
34
+ cppPack,
35
+ elixirPack,
36
+ scalaPack,
37
+ rPack,
38
+ ];
14
39
  export async function runCli(rootPath, options = {}) {
15
40
  const promptFn = options.promptFn ?? defaultPromptFn;
16
41
  const execFn = options.execFn ?? defaultExecFn;
@@ -61,7 +86,7 @@ export async function runCli(rootPath, options = {}) {
61
86
  }
62
87
  return writeGeneratedFiles(rootPath, files);
63
88
  }
64
- async function main() {
89
+ export async function main() {
65
90
  clack.intro("agent-rules-init");
66
91
  if (!hasInteractiveTty()) {
67
92
  console.warn("No se detectó una terminal interactiva (esto pasa a veces en Git Bash en Windows). " +
@@ -96,7 +121,3 @@ async function main() {
96
121
  process.exitCode = 1;
97
122
  }
98
123
  }
99
- const isMainModule = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
100
- if (isMainModule) {
101
- main();
102
- }
@@ -48,11 +48,19 @@ function readTextIfExists(filePath) {
48
48
  return undefined;
49
49
  }
50
50
  }
51
- function findFirst(files, fileName) {
52
- const matches = files.filter((f) => path.basename(f) === fileName);
51
+ function shallowest(matches) {
53
52
  if (matches.length === 0)
54
53
  return undefined;
55
- return matches.reduce((shallowest, candidate) => candidate.split(path.sep).length < shallowest.split(path.sep).length ? candidate : shallowest);
54
+ return matches.reduce((shallowestSoFar, candidate) => candidate.split(path.sep).length < shallowestSoFar.split(path.sep).length ? candidate : shallowestSoFar);
55
+ }
56
+ function findFirst(files, fileName) {
57
+ return shallowest(files.filter((f) => path.basename(f) === fileName));
58
+ }
59
+ function findFirstByExtension(files, extension) {
60
+ return shallowest(files.filter((f) => f.toLowerCase().endsWith(extension)));
61
+ }
62
+ function pickShallowest(paths) {
63
+ return shallowest(paths.filter((p) => p !== undefined));
56
64
  }
57
65
  export function scanRepo(rootPath) {
58
66
  const files = walk(rootPath);
@@ -79,10 +87,34 @@ export function scanRepo(rootPath) {
79
87
  requireDev: rawComposerJson["require-dev"] ?? {},
80
88
  }
81
89
  : undefined;
82
- const pyprojectPath = findFirst(files, "pyproject.toml");
83
- const requirementsPath = findFirst(files, "requirements.txt");
90
+ const pyprojectCandidate = findFirst(files, "pyproject.toml");
91
+ const requirementsCandidate = findFirst(files, "requirements.txt");
92
+ const environmentYmlCandidate = findFirst(files, "environment.yml") ?? findFirst(files, "environment.yaml");
93
+ // Only the shallowest of the three "wins" as the project's Python manifest — otherwise an
94
+ // unrelated pyproject.toml nested inside a vendored/data subdirectory (e.g. a bundled dataset
95
+ // package) would always outrank a real root-level environment.yml just by file type.
96
+ const primaryPythonManifest = pickShallowest([
97
+ pyprojectCandidate,
98
+ requirementsCandidate,
99
+ environmentYmlCandidate,
100
+ ]);
101
+ const pyprojectPath = primaryPythonManifest === pyprojectCandidate ? pyprojectCandidate : undefined;
102
+ const requirementsPath = primaryPythonManifest === requirementsCandidate ? requirementsCandidate : undefined;
103
+ const environmentYmlPath = primaryPythonManifest === environmentYmlCandidate ? environmentYmlCandidate : undefined;
84
104
  const pomPath = findFirst(files, "pom.xml");
85
105
  const buildGradlePath = findFirst(files, "build.gradle") ?? findFirst(files, "build.gradle.kts");
106
+ const gemfilePath = findFirst(files, "Gemfile");
107
+ const goModPath = findFirst(files, "go.mod");
108
+ const cargoTomlPath = findFirst(files, "Cargo.toml");
109
+ const csprojPath = findFirstByExtension(files, ".csproj");
110
+ const packageSwiftPath = findFirst(files, "Package.swift");
111
+ const pubspecYamlPath = findFirst(files, "pubspec.yaml");
112
+ const cmakeListsPath = findFirst(files, "CMakeLists.txt");
113
+ const makefilePath = findFirst(files, "Makefile") ?? findFirst(files, "makefile");
114
+ const mixExsPath = findFirst(files, "mix.exs");
115
+ const buildSbtPath = findFirst(files, "build.sbt");
116
+ const rDescriptionPath = findFirst(files, "DESCRIPTION");
117
+ const renvLockPath = findFirst(files, "renv.lock");
86
118
  return {
87
119
  rootPath,
88
120
  files,
@@ -94,8 +126,23 @@ export function scanRepo(rootPath) {
94
126
  requirementsTxt: requirementsPath
95
127
  ? readTextIfExists(path.join(rootPath, requirementsPath))
96
128
  : undefined,
129
+ environmentYml: environmentYmlPath
130
+ ? readTextIfExists(path.join(rootPath, environmentYmlPath))
131
+ : undefined,
97
132
  pomXml: pomPath ? readTextIfExists(path.join(rootPath, pomPath)) : undefined,
98
133
  buildGradle: buildGradlePath ? readTextIfExists(path.join(rootPath, buildGradlePath)) : undefined,
99
134
  composerJson,
135
+ gemfile: gemfilePath ? readTextIfExists(path.join(rootPath, gemfilePath)) : undefined,
136
+ goMod: goModPath ? readTextIfExists(path.join(rootPath, goModPath)) : undefined,
137
+ cargoToml: cargoTomlPath ? readTextIfExists(path.join(rootPath, cargoTomlPath)) : undefined,
138
+ csproj: csprojPath ? readTextIfExists(path.join(rootPath, csprojPath)) : undefined,
139
+ packageSwift: packageSwiftPath ? readTextIfExists(path.join(rootPath, packageSwiftPath)) : undefined,
140
+ pubspecYaml: pubspecYamlPath ? readTextIfExists(path.join(rootPath, pubspecYamlPath)) : undefined,
141
+ cmakeLists: cmakeListsPath ? readTextIfExists(path.join(rootPath, cmakeListsPath)) : undefined,
142
+ makefile: makefilePath ? readTextIfExists(path.join(rootPath, makefilePath)) : undefined,
143
+ mixExs: mixExsPath ? readTextIfExists(path.join(rootPath, mixExsPath)) : undefined,
144
+ buildSbt: buildSbtPath ? readTextIfExists(path.join(rootPath, buildSbtPath)) : undefined,
145
+ rDescription: rDescriptionPath ? readTextIfExists(path.join(rootPath, rDescriptionPath)) : undefined,
146
+ renvLock: renvLockPath ? readTextIfExists(path.join(rootPath, renvLockPath)) : undefined,
100
147
  };
101
148
  }
@@ -1 +1,64 @@
1
- export * from "agent-rules-pack-types";
1
+ export interface PackageJsonManifest {
2
+ name?: string;
3
+ dependencies: Record<string, string>;
4
+ devDependencies: Record<string, string>;
5
+ scripts: Record<string, string>;
6
+ }
7
+ export interface ComposerJsonManifest {
8
+ require: Record<string, string>;
9
+ requireDev: Record<string, string>;
10
+ }
11
+ export interface RepoSignals {
12
+ rootPath: string;
13
+ files: string[];
14
+ hasFile: (relativePath: string) => boolean;
15
+ hasDir: (relativeDir: string) => boolean;
16
+ packageJson?: PackageJsonManifest;
17
+ pyprojectToml?: string;
18
+ requirementsTxt?: string;
19
+ environmentYml?: string;
20
+ pomXml?: string;
21
+ buildGradle?: string;
22
+ composerJson?: ComposerJsonManifest;
23
+ gemfile?: string;
24
+ goMod?: string;
25
+ cargoToml?: string;
26
+ csproj?: string;
27
+ packageSwift?: string;
28
+ pubspecYaml?: string;
29
+ cmakeLists?: string;
30
+ makefile?: string;
31
+ mixExs?: string;
32
+ buildSbt?: string;
33
+ rDescription?: string;
34
+ renvLock?: string;
35
+ }
36
+ export type Confidence = "high" | "low";
37
+ export interface DetectionField<T> {
38
+ value: T;
39
+ confidence: Confidence;
40
+ }
41
+ export interface DetectionResult {
42
+ packId: string;
43
+ language: string;
44
+ framework?: DetectionField<string>;
45
+ packageManager?: DetectionField<string>;
46
+ testRunner?: DetectionField<string>;
47
+ linter?: DetectionField<string>;
48
+ }
49
+ export interface RuleSet {
50
+ summary: string;
51
+ conventions: string[];
52
+ architectureNotes: string[];
53
+ }
54
+ export interface PromptTemplate {
55
+ id: "review" | "refactor" | "testing";
56
+ title: string;
57
+ body: string;
58
+ }
59
+ export interface Pack {
60
+ id: string;
61
+ detect(signals: RepoSignals): DetectionResult | null;
62
+ rules(detection: DetectionResult): RuleSet;
63
+ promptTemplates(detection: DetectionResult): PromptTemplate[];
64
+ }
@@ -1 +1 @@
1
- export * from "agent-rules-pack-types";
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const cppPack: Pack;
@@ -0,0 +1,70 @@
1
+ const FRAMEWORKS = [
2
+ ["find_package(qt", "qt"],
3
+ ["find_package(boost", "boost"],
4
+ ["find_package(sdl2", "sdl2"],
5
+ ];
6
+ const TEST_RUNNERS = [
7
+ ["gtest", "gtest"],
8
+ ["catch2", "catch2"],
9
+ ["doctest", "doctest"],
10
+ ];
11
+ function detect(signals) {
12
+ const source = signals.cmakeLists ?? signals.makefile;
13
+ if (!source)
14
+ return null;
15
+ const lower = source.toLowerCase();
16
+ let framework = { value: "none", confidence: "low" };
17
+ for (const [needle, label] of FRAMEWORKS) {
18
+ if (lower.includes(needle)) {
19
+ framework = { value: label, confidence: "high" };
20
+ break;
21
+ }
22
+ }
23
+ let testRunner = { value: "unknown", confidence: "low" };
24
+ for (const [needle, label] of TEST_RUNNERS) {
25
+ if (lower.includes(needle)) {
26
+ testRunner = { value: label, confidence: "high" };
27
+ break;
28
+ }
29
+ }
30
+ const packageManager = signals.cmakeLists
31
+ ? { value: "cmake", confidence: "high" }
32
+ : { value: "make", confidence: "high" };
33
+ return { packId: "cpp", language: "C/C++", framework, testRunner, packageManager };
34
+ }
35
+ function rules(detection) {
36
+ const framework = detection.framework?.value ?? "none";
37
+ return {
38
+ summary: `Proyecto C/C++${framework !== "none" ? ` con ${framework}` : ""} (${detection.packageManager?.value}).`,
39
+ conventions: [
40
+ "Sigue el estilo de formato ya usado en el proyecto (revisa si hay un `.clang-format`).",
41
+ `Compila y ejecuta los tests con ${detection.packageManager?.value === "cmake" ? "cmake --build . && ctest" : "make test"} antes de terminar una tarea.`,
42
+ "Gestiona la memoria con cuidado: prefiere RAII/smart pointers sobre `new`/`delete` manuales cuando el proyecto ya lo haga.",
43
+ ],
44
+ architectureNotes: [
45
+ "Mantén los headers con guardas de inclusión (`#pragma once` o include guards) consistentes con el resto del proyecto.",
46
+ "Declara toda dependencia nueva en el sistema de build existente (CMakeLists.txt o Makefile).",
47
+ ],
48
+ };
49
+ }
50
+ function promptTemplates(detection) {
51
+ const framework = detection.framework?.value ?? "el framework del proyecto";
52
+ return [
53
+ {
54
+ id: "review",
55
+ title: "Code Review (C/C++)",
56
+ body: `Revisa el diff actual buscando fugas de memoria, punteros colgantes y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
57
+ },
58
+ {
59
+ id: "refactor",
60
+ title: "Refactor (C/C++)",
61
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
62
+ },
63
+ {
64
+ id: "testing",
65
+ title: "Testing (C/C++)",
66
+ body: `Escribe tests con ${detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : "el framework de tests del proyecto"} para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
67
+ },
68
+ ];
69
+ }
70
+ export const cppPack = { id: "cpp", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const csharpPack: Pack;
@@ -0,0 +1,59 @@
1
+ function detect(signals) {
2
+ const source = signals.csproj;
3
+ if (!source)
4
+ return null;
5
+ const lower = source.toLowerCase();
6
+ const framework = lower.includes("microsoft.aspnetcore")
7
+ ? { value: "aspnet-core", confidence: "high" }
8
+ : { value: "none", confidence: "low" };
9
+ const testRunner = lower.includes("xunit")
10
+ ? { value: "xunit", confidence: "high" }
11
+ : lower.includes("nunit")
12
+ ? { value: "nunit", confidence: "high" }
13
+ : lower.includes("mstest")
14
+ ? { value: "mstest", confidence: "high" }
15
+ : { value: "unknown", confidence: "low" };
16
+ return {
17
+ packId: "csharp",
18
+ language: "C#",
19
+ framework,
20
+ testRunner,
21
+ packageManager: { value: "nuget", confidence: "high" },
22
+ };
23
+ }
24
+ function rules(detection) {
25
+ const framework = detection.framework?.value ?? "none";
26
+ return {
27
+ summary: `Proyecto C#/.NET${framework !== "none" ? ` con ${framework}` : ""} (NuGet).`,
28
+ conventions: [
29
+ "Sigue las convenciones de nombrado de .NET (PascalCase para clases/métodos públicos, camelCase para variables locales).",
30
+ `Ejecuta los tests con \`dotnet test\` antes de terminar una tarea.`,
31
+ "Declara toda dependencia nueva vía NuGet en el .csproj, nunca la añadas manualmente sin registrarla.",
32
+ ],
33
+ architectureNotes: [
34
+ "Respeta la separación en capas (controller/service/repository) si el proyecto ya la usa.",
35
+ "Prefiere inyección de dependencias sobre instanciación manual cuando el framework ya la ofrezca.",
36
+ ],
37
+ };
38
+ }
39
+ function promptTemplates(detection) {
40
+ const framework = detection.framework?.value ?? "el framework del proyecto";
41
+ return [
42
+ {
43
+ id: "review",
44
+ title: "Code Review (C#/.NET)",
45
+ body: `Revisa el diff actual buscando bugs, null-safety y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
46
+ },
47
+ {
48
+ id: "refactor",
49
+ title: "Refactor (C#/.NET)",
50
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
51
+ },
52
+ {
53
+ id: "testing",
54
+ title: "Testing (C#/.NET)",
55
+ body: `Escribe tests con ${detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : "el test runner del proyecto"} para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
56
+ },
57
+ ];
58
+ }
59
+ export const csharpPack = { id: "csharp", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const dartPack: Pack;
@@ -0,0 +1,61 @@
1
+ function detect(signals) {
2
+ const source = signals.pubspecYaml;
3
+ if (!source)
4
+ return null;
5
+ const lower = source.toLowerCase();
6
+ const framework = /^\s*flutter\s*:/m.test(lower)
7
+ ? { value: "flutter", confidence: "high" }
8
+ : lower.includes("shelf")
9
+ ? { value: "shelf", confidence: "high" }
10
+ : { value: "none", confidence: "low" };
11
+ const testRunner = lower.includes("flutter_test")
12
+ ? { value: "flutter test", confidence: "high" }
13
+ : /^\s*test\s*:/m.test(lower)
14
+ ? { value: "dart test", confidence: "high" }
15
+ : { value: "unknown", confidence: "low" };
16
+ return {
17
+ packId: "dart",
18
+ language: "Dart",
19
+ framework,
20
+ testRunner,
21
+ packageManager: { value: "pub", confidence: "high" },
22
+ };
23
+ }
24
+ function rules(detection) {
25
+ const framework = detection.framework?.value ?? "none";
26
+ return {
27
+ summary: `Proyecto Dart${framework !== "none" ? ` con ${framework}` : ""} (pub).`,
28
+ conventions: [
29
+ "Sigue la guía de estilo oficial de Dart (dart.dev/effective-dart/style).",
30
+ `Ejecuta los tests con ${detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : "el test runner del proyecto"} antes de terminar una tarea.`,
31
+ "Declara toda dependencia nueva en pubspec.yaml, nunca la instales sin registrarla.",
32
+ ],
33
+ architectureNotes: [
34
+ framework === "flutter"
35
+ ? "Separa la lógica de negocio de los widgets cuando el proyecto ya siga ese patrón (p. ej. BLoC/Provider/Riverpod)."
36
+ : "Mantén los módulos con una responsabilidad clara.",
37
+ "Prefiere `final`/`const` sobre variables mutables cuando sea posible.",
38
+ ],
39
+ };
40
+ }
41
+ function promptTemplates(detection) {
42
+ const framework = detection.framework?.value ?? "el framework del proyecto";
43
+ return [
44
+ {
45
+ id: "review",
46
+ title: "Code Review (Dart)",
47
+ body: `Revisa el diff actual buscando bugs y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
48
+ },
49
+ {
50
+ id: "refactor",
51
+ title: "Refactor (Dart)",
52
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
53
+ },
54
+ {
55
+ id: "testing",
56
+ title: "Testing (Dart)",
57
+ body: `Escribe tests con ${detection.testRunner?.value !== "unknown" ? detection.testRunner?.value : "el test runner del proyecto"} para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
58
+ },
59
+ ];
60
+ }
61
+ export const dartPack = { id: "dart", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const elixirPack: Pack;
@@ -0,0 +1,52 @@
1
+ function detect(signals) {
2
+ const source = signals.mixExs;
3
+ if (!source)
4
+ return null;
5
+ const lower = source.toLowerCase();
6
+ const framework = lower.includes(":phoenix")
7
+ ? { value: "phoenix", confidence: "high" }
8
+ : { value: "none", confidence: "low" };
9
+ return {
10
+ packId: "elixir",
11
+ language: "Elixir",
12
+ framework,
13
+ testRunner: { value: "mix test", confidence: "high" },
14
+ packageManager: { value: "mix", confidence: "high" },
15
+ };
16
+ }
17
+ function rules(detection) {
18
+ const framework = detection.framework?.value ?? "none";
19
+ return {
20
+ summary: `Proyecto Elixir${framework !== "none" ? ` con ${framework}` : ""} (mix).`,
21
+ conventions: [
22
+ "Sigue la guía de estilo oficial de Elixir; ejecuta `mix format` antes de terminar una tarea.",
23
+ "Ejecuta los tests con `mix test` antes de terminar una tarea.",
24
+ "Prefiere pattern matching y pipelines (`|>`) sobre anidar llamadas de función.",
25
+ ],
26
+ architectureNotes: [
27
+ "Respeta la separación entre contextos (lógica de negocio) y la capa web si el proyecto ya usa Phoenix.",
28
+ "Declara toda dependencia nueva en `mix.exs` y mantén `mix.lock` sincronizado.",
29
+ ],
30
+ };
31
+ }
32
+ function promptTemplates(detection) {
33
+ const framework = detection.framework?.value ?? "el framework del proyecto";
34
+ return [
35
+ {
36
+ id: "review",
37
+ title: "Code Review (Elixir)",
38
+ body: `Revisa el diff actual buscando bugs, procesos sin supervisar correctamente y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
39
+ },
40
+ {
41
+ id: "refactor",
42
+ title: "Refactor (Elixir)",
43
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
44
+ },
45
+ {
46
+ id: "testing",
47
+ title: "Testing (Elixir)",
48
+ body: `Escribe tests con \`mix test\` (ExUnit) para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
49
+ },
50
+ ];
51
+ }
52
+ export const elixirPack = { id: "elixir", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const goPack: Pack;
@@ -0,0 +1,62 @@
1
+ const FRAMEWORKS = [
2
+ ["gin-gonic/gin", "gin"],
3
+ ["labstack/echo", "echo"],
4
+ ["gofiber/fiber", "fiber"],
5
+ ["go-chi/chi", "chi"],
6
+ ];
7
+ function detect(signals) {
8
+ const source = signals.goMod;
9
+ if (!source)
10
+ return null;
11
+ const lower = source.toLowerCase();
12
+ let framework = { value: "none", confidence: "low" };
13
+ for (const [needle, label] of FRAMEWORKS) {
14
+ if (lower.includes(needle)) {
15
+ framework = { value: label, confidence: "high" };
16
+ break;
17
+ }
18
+ }
19
+ return {
20
+ packId: "go",
21
+ language: "Go",
22
+ framework,
23
+ testRunner: { value: "go test", confidence: "high" },
24
+ packageManager: { value: "go modules", confidence: "high" },
25
+ };
26
+ }
27
+ function rules(detection) {
28
+ const framework = detection.framework?.value ?? "none";
29
+ return {
30
+ summary: `Proyecto Go${framework !== "none" ? ` con ${framework}` : ""} (go modules).`,
31
+ conventions: [
32
+ "Sigue el formato estándar de `gofmt`; no introduzcas estilos alternativos.",
33
+ "Ejecuta los tests con `go test ./...` antes de terminar una tarea.",
34
+ "Maneja los errores explícitamente (`if err != nil`); no los ignores en silencio.",
35
+ ],
36
+ architectureNotes: [
37
+ "Mantén los paquetes con una responsabilidad clara; evita paquetes `util` genéricos.",
38
+ "Declara toda dependencia nueva vía `go get` y mantén `go.mod`/`go.sum` sincronizados.",
39
+ ],
40
+ };
41
+ }
42
+ function promptTemplates(detection) {
43
+ const framework = detection.framework?.value ?? "el framework del proyecto";
44
+ return [
45
+ {
46
+ id: "review",
47
+ title: "Code Review (Go)",
48
+ body: `Revisa el diff actual buscando bugs, manejo de errores omitido y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
49
+ },
50
+ {
51
+ id: "refactor",
52
+ title: "Refactor (Go)",
53
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
54
+ },
55
+ {
56
+ id: "testing",
57
+ title: "Testing (Go)",
58
+ body: `Escribe tests con \`go test\` para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
59
+ },
60
+ ];
61
+ }
62
+ export const goPack = { id: "go", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const javaPack: Pack;
@@ -0,0 +1,55 @@
1
+ function detect(signals) {
2
+ const source = signals.pomXml ?? signals.buildGradle;
3
+ if (!source)
4
+ return null;
5
+ // A Gradle build that applies the Kotlin plugin is a Kotlin project, not Java —
6
+ // defer entirely to the Kotlin pack instead of also reporting a spurious Java match.
7
+ if (/kotlin\(|org\.jetbrains\.kotlin/i.test(source))
8
+ return null;
9
+ const framework = /spring/i.test(source)
10
+ ? { value: "spring", confidence: "high" }
11
+ : { value: "none", confidence: "low" };
12
+ const packageManager = signals.pomXml
13
+ ? { value: "maven", confidence: "high" }
14
+ : { value: "gradle", confidence: "high" };
15
+ const testRunner = /junit/i.test(source)
16
+ ? { value: "junit", confidence: "high" }
17
+ : { value: "unknown", confidence: "low" };
18
+ return { packId: "java", language: "Java", framework, packageManager, testRunner };
19
+ }
20
+ function rules(detection) {
21
+ const framework = detection.framework?.value ?? "none";
22
+ return {
23
+ summary: `Proyecto Java${framework !== "none" ? ` con ${framework}` : ""} (${detection.packageManager?.value}).`,
24
+ conventions: [
25
+ "Sigue las convenciones de nombrado estándar de Java (PascalCase para clases, camelCase para métodos).",
26
+ `Ejecuta los tests con ${detection.packageManager?.value === "maven" ? "mvn test" : "gradle test"} antes de terminar una tarea.`,
27
+ "No añadas dependencias nuevas sin declararlas en el gestor de build existente.",
28
+ ],
29
+ architectureNotes: [
30
+ "Respeta la separación en capas (controller/service/repository) si el proyecto ya la usa.",
31
+ "Prefiere inyección de dependencias sobre instanciación manual cuando el framework ya la ofrezca.",
32
+ ],
33
+ };
34
+ }
35
+ function promptTemplates(detection) {
36
+ const framework = detection.framework?.value ?? "el framework del proyecto";
37
+ return [
38
+ {
39
+ id: "review",
40
+ title: "Code Review (Java)",
41
+ body: `Revisa el diff actual buscando bugs, null-safety y desviaciones de las convenciones de ${framework}. Señala solo problemas concretos con línea de archivo.`,
42
+ },
43
+ {
44
+ id: "refactor",
45
+ title: "Refactor (Java)",
46
+ body: `Propón refactors que reduzcan duplicación y mejoren la legibilidad sin cambiar comportamiento observable.`,
47
+ },
48
+ {
49
+ id: "testing",
50
+ title: "Testing (Java)",
51
+ body: `Escribe tests con ${detection.testRunner?.value ?? "el test runner del proyecto"} para el código señalado. Cubre el camino feliz y al menos un caso límite.`,
52
+ },
53
+ ];
54
+ }
55
+ export const javaPack = { id: "java", detect, rules, promptTemplates };
@@ -0,0 +1,2 @@
1
+ import type { Pack } from "../core/types.js";
2
+ export declare const jsTsPack: Pack;