openprompt-lang 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.
Files changed (90) hide show
  1. package/README.md +483 -32
  2. package/bin/cli.js +232 -41
  3. package/bin/create.js +135 -0
  4. package/bin/lint.js +20 -21
  5. package/docs/COMMANDS.md +200 -127
  6. package/docs/COMMITS/INDEX.md +1 -0
  7. package/docs/PROMPT_AI_CONTEXT.md +99 -0
  8. package/docs/langs/dotnet.md +36 -0
  9. package/docs/langs/java-spring.md +45 -0
  10. package/docs/langs/python-fastapi.md +35 -0
  11. package/docs/langs/unity.md +30 -0
  12. package/docs/langs/vue-nuxt.md +36 -0
  13. package/package.json +31 -3
  14. package/scaffolds/.cursorrules +6 -0
  15. package/scaffolds/AGENTS.md +27 -0
  16. package/scaffolds/Dockerfile +11 -0
  17. package/scaffolds/capacitor.config.ts +17 -0
  18. package/scaffolds/netlify.toml +8 -0
  19. package/scaffolds/prompt-lang.json +15 -0
  20. package/scaffolds/railway.json +12 -0
  21. package/scaffolds/tailwind.config.js +8 -0
  22. package/scaffolds/tauri.conf.json +26 -0
  23. package/schemas/language-module.json +116 -0
  24. package/schemas/prompt-lang.json +38 -3
  25. package/schemas/structures.json +145 -0
  26. package/src/ai/prompt-builder.js +184 -0
  27. package/src/ai/providers.js +247 -0
  28. package/src/annotations/registry.js +39 -0
  29. package/src/annotations/tags.json +24 -0
  30. package/src/commands/ai-gen.js +161 -0
  31. package/src/commands/component.js +242 -212
  32. package/src/commands/context.js +184 -109
  33. package/src/commands/extract.js +242 -0
  34. package/src/commands/figma.js +15 -15
  35. package/src/commands/init.js +197 -93
  36. package/src/commands/integrate.js +406 -0
  37. package/src/commands/lang.js +148 -0
  38. package/src/commands/qa-gen.js +139 -0
  39. package/src/commands/scaffold.js +127 -0
  40. package/src/commands/suggest.js +24 -14
  41. package/src/commands/teach.js +110 -0
  42. package/src/commands/validate.js +143 -83
  43. package/src/commands/wizard.js +456 -0
  44. package/src/generators/figma-prompt.js +20 -12
  45. package/src/language-service/plugin.cjs +94 -0
  46. package/src/language-service/plugin.d.ts +6 -0
  47. package/src/mcp-server.js +605 -0
  48. package/src/templates/langs/react/INDEX.json +262 -0
  49. package/src/templates/langs/react/MODULE.json +166 -0
  50. package/src/templates/langs/react/templates/hooks/useAuth.template.ts +134 -0
  51. package/src/templates/langs/react/templates/hooks/useDebounce.template.ts +45 -0
  52. package/src/templates/langs/react/templates/hooks/useForm.template.ts +146 -0
  53. package/src/templates/langs/react/templates/hooks/usePagination.template.ts +108 -0
  54. package/src/templates/langs/react/templates/services/apiService.template.ts +123 -0
  55. package/src/templates/langs/react/templates/ui/Button.template.tsx +87 -0
  56. package/src/templates/langs/react/templates/ui/Card.template.tsx +85 -0
  57. package/src/templates/langs/react/templates/ui/DataTable.template.tsx +163 -0
  58. package/src/templates/langs/react/templates/ui/Input.template.tsx +96 -0
  59. package/src/templates/langs/react/templates/ui/Modal.template.tsx +133 -0
  60. package/src/templates/langs/react/templates/ui/Select.template.tsx +99 -0
  61. package/src/templates/langs/vue/INDEX.json +246 -0
  62. package/src/templates/langs/vue/MODULE.json +105 -0
  63. package/src/templates/langs/vue/templates/composables/useAuth.template.ts +106 -0
  64. package/src/templates/langs/vue/templates/composables/useDebounce.template.ts +47 -0
  65. package/src/templates/langs/vue/templates/composables/useFetch.template.ts +54 -0
  66. package/src/templates/langs/vue/templates/composables/useForm.template.ts +127 -0
  67. package/src/templates/langs/vue/templates/composables/usePagination.template.ts +98 -0
  68. package/src/templates/langs/vue/templates/services/apiService.template.ts +116 -0
  69. package/src/templates/langs/vue/templates/ui/Button.template.vue +79 -0
  70. package/src/templates/langs/vue/templates/ui/Card.template.vue +73 -0
  71. package/src/templates/langs/vue/templates/ui/DataTable.template.vue +115 -0
  72. package/src/templates/langs/vue/templates/ui/Input.template.vue +70 -0
  73. package/src/templates/langs/vue/templates/ui/Modal.template.vue +112 -0
  74. package/src/templates/langs/vue/templates/ui/Select.template.vue +77 -0
  75. package/src/templates/scripts/log-actividad.sh +32 -0
  76. package/src/templates/scripts/log-commit.sh +35 -0
  77. package/src/templates/scripts/log-error.sh +45 -0
  78. package/src/templates/scripts/validate.sh +23 -0
  79. package/src/ts-transformer/index.cjs +86 -0
  80. package/src/utils/ai.js +35 -53
  81. package/src/utils/annotations.js +260 -214
  82. package/src/utils/config.js +61 -13
  83. package/src/utils/error-learner.js +203 -0
  84. package/src/utils/file-utils.js +119 -0
  85. package/src/utils/language-loader.js +167 -0
  86. package/src/utils/template-utils.js +45 -0
  87. package/src/vite-plugin/index.js +54 -0
  88. package/vscode-extension/package.json +23 -2
  89. package/vscode-extension/snippets/promptlang.json +1 -3
  90. package/vscode-extension/syntaxes/annotations-code.tmGrammar.json +15 -0
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ // @template
3
+ // @id: select-shadcn-vue
4
+ // @category: ui/form
5
+ // @purpose: dropdown, option-picker, multi-select
6
+ // @framework: vue
7
+ // @style: shadcn-vue
8
+ // @variants: [default, error, multiple]
9
+ // @sizes: [sm, default, lg]
10
+ // @darkMode: true
11
+ // @responsive: true
12
+ // @deps: [vue]
13
+ // @props: { label: string, options: Option[], placeholder: string, error?: string }
14
+ // @states: [idle, focused, filled, error, disabled]
15
+ // @example: <Select label="Country" v-model="country" :options="countries" />
16
+ // @teachMe
17
+ //
18
+ // ## Anatomy
19
+ // Native select dropdown with custom styling and v-model support.
20
+ // Works with arrays of { value, label } objects.
21
+ //
22
+ // @goodPractice: Use native select for better a11y and mobile support
23
+ // @goodPractice: Provide placeholder option with disabled selected
24
+ // @goodPractice: Type options as generic for type safety
25
+
26
+ import { computed } from "vue"
27
+
28
+ interface SelectOption {
29
+ value: string | number
30
+ label: string
31
+ disabled?: boolean
32
+ }
33
+
34
+ const model = defineModel<string | number>({ default: "" })
35
+
36
+ const props = withDefaults(defineProps<{
37
+ label?: string
38
+ options?: SelectOption[]
39
+ placeholder?: string
40
+ error?: string
41
+ disabled?: boolean
42
+ }>(), {
43
+ options: () => [],
44
+ placeholder: "Select an option",
45
+ disabled: false,
46
+ })
47
+
48
+ const selectClasses = computed(() => {
49
+ const base = "flex h-10 w-full rounded-lg border bg-white px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-950 dark:text-gray-100"
50
+ const borderColor = props.error
51
+ ? "border-red-500 focus-visible:ring-red-500"
52
+ : "border-gray-300 focus-visible:ring-blue-500 dark:border-gray-600"
53
+ return [base, borderColor].join(" ")
54
+ })
55
+ </script>
56
+
57
+ <template>
58
+ <div class="flex flex-col gap-1.5">
59
+ <label v-if="label" class="text-sm font-medium text-gray-700 dark:text-gray-300">
60
+ {{ label }}
61
+ </label>
62
+ <div class="relative">
63
+ <select v-model="model" :disabled="disabled" :class="selectClasses">
64
+ <option value="" disabled selected>{{ placeholder }}</option>
65
+ <option
66
+ v-for="opt in options"
67
+ :key="opt.value"
68
+ :value="opt.value"
69
+ :disabled="opt.disabled"
70
+ >
71
+ {{ opt.label }}
72
+ </option>
73
+ </select>
74
+ </div>
75
+ <p v-if="error" class="text-sm text-red-500">{{ error }}</p>
76
+ </div>
77
+ </template>
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+ # @generated by openPrompt-Lang
3
+ # Uso: ./scripts/log-actividad.sh "Objetivo de la sesión"
4
+
5
+ DATE=$(date +%Y-%m-%d)
6
+ DIR="docs/LOGS/ACTIVIDAD/$(date +%Y-%m)"
7
+ mkdir -p "$DIR"
8
+ FILENAME="${DIR}/${DATE}.md"
9
+
10
+ if [ ! -f "$FILENAME" ]; then
11
+ cat > "$FILENAME" << EOF
12
+ # Actividad — ${DATE}
13
+
14
+ ## Sesión de trabajo: $1
15
+ **Duración:**
16
+ **Objetivo:** $1
17
+
18
+ ### Tareas realizadas
19
+ 1.
20
+
21
+ ### Errores encontrados
22
+
23
+ ### Decisiones tomadas
24
+
25
+ ### Próxima sesión
26
+
27
+ EOF
28
+ echo "Log de actividad creado: $FILENAME"
29
+ else
30
+ echo "Log ya existe: $FILENAME"
31
+ echo "Agrega manualmente las tareas al final del archivo."
32
+ fi
@@ -0,0 +1,35 @@
1
+ #!/bin/bash
2
+ # @generated by openPrompt-Lang
3
+ # Uso: ./scripts/log-commit.sh
4
+
5
+ HASH=$(git log -1 --format="%H")
6
+ DATE=$(git log -1 --format="%ad" --date=short)
7
+ MSG=$(git log -1 --format="%s")
8
+ FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only HEAD)
9
+ VERSION=$(git tag --points-at HEAD | head -1)
10
+
11
+ FILENAME="docs/COMMITS/${VERSION:-sin-version}-$(date +%Y%m%d).md"
12
+
13
+ cat > "$FILENAME" << EOF
14
+ ## [${VERSION:-sin-version}] - ${DATE}
15
+
16
+ ### Commit: ${MSG}
17
+ **Hash:** ${HASH}
18
+ **Fecha:** ${DATE}
19
+ **Módulo:**
20
+ **Versión:** ${VERSION:-sin-version}
21
+
22
+ #### Cambios realizados
23
+ $(echo "$MSG" | sed 's/^/\n- /')
24
+
25
+ #### Archivos modificados
26
+ $(echo "$FILES" | sed 's/^/- `/' | sed 's/$/`/')
27
+
28
+ #### Criterios de aceptación cumplidos
29
+ - [ ]
30
+
31
+ #### Notas
32
+
33
+ EOF
34
+
35
+ echo "Commit log creado: $FILENAME"
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # @generated by openPrompt-Lang
3
+ # Uso: ./scripts/log-error.sh "Título del error" API HIGH auth
4
+
5
+ TITLE="$1"
6
+ TYPE="$2"
7
+ SEVERITY="$3"
8
+ MODULE="$4"
9
+ DATE=$(date +%Y-%m-%d)
10
+ TIME=$(date +%H:%M)
11
+ FILENAME="docs/LOGS/ERRORES/${TYPE}/$(date +%Y-%m-%d)-$(echo $TITLE | tr '[:upper:]' '[:lower:]' | tr ' ' '-').md"
12
+
13
+ mkdir -p "docs/LOGS/ERRORES/${TYPE}"
14
+
15
+ cat > "$FILENAME" << EOF
16
+ # Error: ${TITLE}
17
+
18
+ **Fecha:** ${DATE} ${TIME}
19
+ **Tipo:** ${TYPE}
20
+ **Severidad:** ${SEVERITY}
21
+ **Módulo:** ${MODULE}
22
+ **Contexto:**
23
+
24
+ ## Descripción
25
+
26
+
27
+ ## Traza / Log
28
+ \`\`\`
29
+
30
+ \`\`\`
31
+
32
+ ## Causa raíz
33
+
34
+
35
+ ## Solución aplicada
36
+
37
+
38
+ ## Prevención
39
+
40
+
41
+ ## Archivos relacionados
42
+
43
+ EOF
44
+
45
+ echo "Log creado: $FILENAME"
@@ -0,0 +1,23 @@
1
+ #!/bin/bash
2
+ # @generated by openPrompt-Lang
3
+ # Pipeline de validación unificado
4
+ set -e
5
+
6
+ echo "=== Pipeline de Validación (openPrompt-Lang) ==="
7
+
8
+ echo "[1/5] Linting..."
9
+ npm run lint:check || { echo "❌ Lint falló"; exit 1; }
10
+
11
+ echo "[2/5] TypeScript check..."
12
+ npm run type:check || { echo "❌ TypeScript falló"; exit 1; }
13
+
14
+ echo "[3/5] react-doctor..."
15
+ npm run quality:doctor || { echo "❌ react-doctor encontró problemas"; exit 1; }
16
+
17
+ echo "[4/5] Tests..."
18
+ npm run test:unit || { echo "❌ Tests fallaron"; exit 1; }
19
+
20
+ echo "[5/5] openPrompt-Lang validate..."
21
+ npx openPrompt-Lang validate || { echo "❌ Validación falló"; exit 1; }
22
+
23
+ echo "=== ✅ Pipeline completo — Código válido ==="
@@ -0,0 +1,86 @@
1
+ var builtinTags = [
2
+ "use",
3
+ "kind",
4
+ "contract",
5
+ "props",
6
+ "state",
7
+ "limit",
8
+ "forbidden",
9
+ "compose",
10
+ "deps",
11
+ "platform",
12
+ "scope",
13
+ "test",
14
+ "meta",
15
+ "pattern",
16
+ "learn-error",
17
+ ]
18
+
19
+ function countNesting(line) {
20
+ var depth = 0
21
+ for (var i = 0; i < line.length; i++) {
22
+ if (line[i] === "(" || line[i] === "{" || line[i] === "[") depth++
23
+ if (line[i] === ")" || line[i] === "}" || line[i] === "]") depth--
24
+ }
25
+ return depth
26
+ }
27
+
28
+ function stripAnnotations(code, customTags) {
29
+ var tags = builtinTags.concat(customTags || [])
30
+ var escaped = tags.map(function (t) {
31
+ return t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
32
+ })
33
+ var pattern = new RegExp("^\\s*@(" + escaped.join("|") + ")\\(")
34
+ var lines = code.split("\n")
35
+ var result = []
36
+ var i = 0
37
+
38
+ while (i < lines.length) {
39
+ if (pattern.test(lines[i].trim())) {
40
+ var depth = countNesting(lines[i])
41
+ while (depth > 0 && i + 1 < lines.length) {
42
+ i++
43
+ depth += countNesting(lines[i])
44
+ }
45
+ i++
46
+ continue
47
+ }
48
+ result.push(lines[i])
49
+ i++
50
+ }
51
+
52
+ return result.join("\n")
53
+ }
54
+
55
+ function createTransformer(program, config) {
56
+ var customTags = (config && config.customTags) || []
57
+ var tags = builtinTags.concat(customTags)
58
+
59
+ return function (ctx) {
60
+ return function (sourceFile) {
61
+ var cleaned = stripAnnotations(sourceFile.text, tags)
62
+ if (cleaned === sourceFile.text) return sourceFile
63
+
64
+ var ts
65
+ try {
66
+ ts = require("typescript")
67
+ } catch (e) {
68
+ return sourceFile
69
+ }
70
+
71
+ var sf = ts.createSourceFile(
72
+ sourceFile.fileName,
73
+ cleaned,
74
+ ts.ScriptTarget.Latest,
75
+ true,
76
+ sourceFile.languageVariant || ts.ScriptKind.TS
77
+ )
78
+ return sf
79
+ }
80
+ }
81
+ }
82
+
83
+ module.exports = {
84
+ stripAnnotations: stripAnnotations,
85
+ createTransformer: createTransformer,
86
+ }
package/src/utils/ai.js CHANGED
@@ -1,39 +1,42 @@
1
1
  /**
2
2
  * openPrompt-Lang AI module
3
- *
3
+ *
4
4
  * Proporciona integración con servicios de IA (OpenAI, opencode, etc.)
5
5
  * para sugerencias automáticas de stack, estructura y scaffolding.
6
- *
6
+ *
7
+ * Usa el registry de providers de src/ai/providers.js para evitar
8
+ * duplicación de lógica de fetch a APIs externas.
9
+ *
7
10
  * Si no hay API key ni opencode, genera un plan detallado para que
8
11
  * la IA externa lo ejecute.
9
12
  */
10
13
 
11
- import chalk from "chalk";
14
+ import { generateCode } from "../ai/providers.js"
15
+
16
+ const SYSTEM_PROMPT =
17
+ "Eres un arquitecto de software. Responde siempre en JSON con keys: stack, folders, modules, priorities"
12
18
 
13
19
  export async function suggestStack(description) {
14
20
  try {
15
- // Intenta usar opencode si está disponible
16
- const result = await tryOpencode(description);
17
- if (result) return result;
21
+ const result = await tryOpencode(description)
22
+ if (result) return result
18
23
  } catch {
19
24
  // fallback
20
25
  }
21
26
 
22
27
  try {
23
- // Intenta usar OpenAI si hay API key
24
- const result = await tryOpenAI(description);
25
- if (result) return result;
28
+ const result = await tryAIProvider(description)
29
+ if (result) return result
26
30
  } catch {
27
31
  // fallback
28
32
  }
29
33
 
30
- // Fallback: generar plan para IA externa
31
- return generateFallbackPlan(description);
34
+ return generateFallbackPlan(description)
32
35
  }
33
36
 
34
37
  async function tryOpencode(description) {
35
38
  try {
36
- const { execSync } = await import("child_process");
39
+ const { execSync } = await import("child_process")
37
40
  const prompt = `Eres un arquitecto de software. Analiza esta descripción de proyecto y sugiere:
38
41
  1. Stack tecnológico (React/Vue/Angular, base de datos, hosting)
39
42
  2. Estructura de carpetas inicial
@@ -42,54 +45,33 @@ async function tryOpencode(description) {
42
45
 
43
46
  Descripción: ${description}
44
47
 
45
- Formato de respuesta: JSON con keys: stack, folders, modules, priorities`;
48
+ Formato de respuesta: JSON con keys: stack, folders, modules, priorities`
46
49
 
47
50
  const result = execSync(`opencode prompt "${prompt}"`, {
48
51
  encoding: "utf-8",
49
52
  timeout: 30000,
50
- }).trim();
53
+ }).trim()
51
54
 
52
- return JSON.parse(result);
55
+ return JSON.parse(result)
53
56
  } catch {
54
- return null;
57
+ return null
55
58
  }
56
59
  }
57
60
 
58
- async function tryOpenAI(description) {
59
- const apiKey = process.env.OPENAI_API_KEY || process.env.OPENPROMPT_API_KEY;
60
- if (!apiKey) return null;
61
-
62
- try {
63
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
64
- method: "POST",
65
- headers: {
66
- "Content-Type": "application/json",
67
- Authorization: `Bearer ${apiKey}`,
68
- },
69
- body: JSON.stringify({
70
- model: "gpt-4",
71
- messages: [
72
- {
73
- role: "system",
74
- content:
75
- "Eres un arquitecto de software. Responde siempre en JSON con keys: stack, folders, modules, priorities",
76
- },
77
- { role: "user", content: `Sugiere stack y estructura para: ${description}` },
78
- ],
79
- temperature: 0.3,
80
- }),
81
- });
82
-
83
- const data = await response.json();
84
- const content = data.choices?.[0]?.message?.content;
85
- if (content) {
86
- return JSON.parse(content.replace(/```json/g, "").replace(/```/g, "").trim());
87
- }
88
- } catch {
89
- // fallback
90
- }
91
-
92
- return null;
61
+ async function tryAIProvider(description) {
62
+ const prompt = `Sugiere stack y estructura para: ${description}`
63
+ const content = await generateCode(prompt, {
64
+ systemPrompt: SYSTEM_PROMPT,
65
+ temperature: 0.3,
66
+ maxTokens: 2048,
67
+ })
68
+ if (!content) return null
69
+ return JSON.parse(
70
+ content
71
+ .replace(/```json?/g, "")
72
+ .replace(/```/g, "")
73
+ .trim()
74
+ )
93
75
  }
94
76
 
95
77
  function generateFallbackPlan(description) {
@@ -137,7 +119,7 @@ Lista las tareas P0 en orden:
137
119
  - Sigue los límites: hook ≤80 líneas, componente ≤120, página ≤200, servicio ≤150
138
120
  - 100% Tailwind utility classes
139
121
  - Cada componente debe manejar estados: loading, empty, error, success
140
- `;
122
+ `
141
123
 
142
- return { plan, source: "fallback" };
124
+ return { plan, source: "fallback" }
143
125
  }