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.
- package/README.md +483 -32
- package/bin/cli.js +232 -41
- package/bin/create.js +135 -0
- package/bin/lint.js +20 -21
- package/docs/COMMANDS.md +200 -127
- package/docs/COMMITS/INDEX.md +1 -0
- package/docs/PROMPT_AI_CONTEXT.md +99 -0
- package/docs/langs/dotnet.md +36 -0
- package/docs/langs/java-spring.md +45 -0
- package/docs/langs/python-fastapi.md +35 -0
- package/docs/langs/unity.md +30 -0
- package/docs/langs/vue-nuxt.md +36 -0
- package/package.json +31 -3
- package/scaffolds/.cursorrules +6 -0
- package/scaffolds/AGENTS.md +27 -0
- package/scaffolds/Dockerfile +11 -0
- package/scaffolds/capacitor.config.ts +17 -0
- package/scaffolds/netlify.toml +8 -0
- package/scaffolds/prompt-lang.json +15 -0
- package/scaffolds/railway.json +12 -0
- package/scaffolds/tailwind.config.js +8 -0
- package/scaffolds/tauri.conf.json +26 -0
- package/schemas/language-module.json +116 -0
- package/schemas/prompt-lang.json +38 -3
- package/schemas/structures.json +145 -0
- package/src/ai/prompt-builder.js +184 -0
- package/src/ai/providers.js +247 -0
- package/src/annotations/registry.js +39 -0
- package/src/annotations/tags.json +24 -0
- package/src/commands/ai-gen.js +161 -0
- package/src/commands/component.js +242 -212
- package/src/commands/context.js +184 -109
- package/src/commands/extract.js +242 -0
- package/src/commands/figma.js +15 -15
- package/src/commands/init.js +197 -93
- package/src/commands/integrate.js +406 -0
- package/src/commands/lang.js +148 -0
- package/src/commands/qa-gen.js +139 -0
- package/src/commands/scaffold.js +127 -0
- package/src/commands/suggest.js +24 -14
- package/src/commands/teach.js +110 -0
- package/src/commands/validate.js +143 -83
- package/src/commands/wizard.js +456 -0
- package/src/generators/figma-prompt.js +20 -12
- package/src/language-service/plugin.cjs +94 -0
- package/src/language-service/plugin.d.ts +6 -0
- package/src/mcp-server.js +605 -0
- package/src/templates/langs/react/INDEX.json +262 -0
- package/src/templates/langs/react/MODULE.json +166 -0
- package/src/templates/langs/react/templates/hooks/useAuth.template.ts +134 -0
- package/src/templates/langs/react/templates/hooks/useDebounce.template.ts +45 -0
- package/src/templates/langs/react/templates/hooks/useForm.template.ts +146 -0
- package/src/templates/langs/react/templates/hooks/usePagination.template.ts +108 -0
- package/src/templates/langs/react/templates/services/apiService.template.ts +123 -0
- package/src/templates/langs/react/templates/ui/Button.template.tsx +87 -0
- package/src/templates/langs/react/templates/ui/Card.template.tsx +85 -0
- package/src/templates/langs/react/templates/ui/DataTable.template.tsx +163 -0
- package/src/templates/langs/react/templates/ui/Input.template.tsx +96 -0
- package/src/templates/langs/react/templates/ui/Modal.template.tsx +133 -0
- package/src/templates/langs/react/templates/ui/Select.template.tsx +99 -0
- package/src/templates/langs/vue/INDEX.json +246 -0
- package/src/templates/langs/vue/MODULE.json +105 -0
- package/src/templates/langs/vue/templates/composables/useAuth.template.ts +106 -0
- package/src/templates/langs/vue/templates/composables/useDebounce.template.ts +47 -0
- package/src/templates/langs/vue/templates/composables/useFetch.template.ts +54 -0
- package/src/templates/langs/vue/templates/composables/useForm.template.ts +127 -0
- package/src/templates/langs/vue/templates/composables/usePagination.template.ts +98 -0
- package/src/templates/langs/vue/templates/services/apiService.template.ts +116 -0
- package/src/templates/langs/vue/templates/ui/Button.template.vue +79 -0
- package/src/templates/langs/vue/templates/ui/Card.template.vue +73 -0
- package/src/templates/langs/vue/templates/ui/DataTable.template.vue +115 -0
- package/src/templates/langs/vue/templates/ui/Input.template.vue +70 -0
- package/src/templates/langs/vue/templates/ui/Modal.template.vue +112 -0
- package/src/templates/langs/vue/templates/ui/Select.template.vue +77 -0
- package/src/templates/scripts/log-actividad.sh +32 -0
- package/src/templates/scripts/log-commit.sh +35 -0
- package/src/templates/scripts/log-error.sh +45 -0
- package/src/templates/scripts/validate.sh +23 -0
- package/src/ts-transformer/index.cjs +86 -0
- package/src/utils/ai.js +35 -53
- package/src/utils/annotations.js +260 -214
- package/src/utils/config.js +61 -13
- package/src/utils/error-learner.js +203 -0
- package/src/utils/file-utils.js +119 -0
- package/src/utils/language-loader.js +167 -0
- package/src/utils/template-utils.js +45 -0
- package/src/vite-plugin/index.js +54 -0
- package/vscode-extension/package.json +23 -2
- package/vscode-extension/snippets/promptlang.json +1 -3
- 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
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
}
|