zyn-ai 1.2.0 → 1.2.1
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/package.json +38 -8
- package/src/providers/catalog.js +302 -0
- package/.github/workflows/publish.yml +0 -23
- package/data/models.example.json +0 -15
- package/data/skills/code-style.md +0 -79
- package/data/skills/completion.md +0 -20
- package/data/skills/core.md +0 -35
- package/data/skills/debugging.md +0 -279
- package/data/skills/domains.md +0 -83
- package/data/skills/frontend_design.md +0 -33
- package/data/skills/methodology.md +0 -84
- package/data/skills/reasoning.md +0 -62
- package/data/skills/testing.md +0 -24
- package/data/skills/thinking.md +0 -146
- package/data/skills/tools.md +0 -102
- package/data/skills/web-agent.md +0 -67
package/package.json
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zyn-ai",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "Production-ready AI agent for CLI and web with real tool execution and automation",
|
|
5
5
|
"author": "Maycol y Ado",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"ai-agent",
|
|
8
|
+
"cli-ai",
|
|
9
|
+
"terminal-ai",
|
|
10
|
+
"automation-agent",
|
|
11
|
+
"developer-tools",
|
|
12
|
+
"ai-cli",
|
|
13
|
+
"nodejs-cli",
|
|
14
|
+
"productivity-tool",
|
|
15
|
+
"local-ai-agent",
|
|
16
|
+
"command-line-ai",
|
|
17
|
+
"web-ai-agent",
|
|
18
|
+
"zyn"
|
|
19
|
+
],
|
|
6
20
|
"bin": {
|
|
7
|
-
"Zyn": "./zyn.js",
|
|
8
21
|
"zyn": "./zyn.js"
|
|
9
22
|
},
|
|
10
23
|
"type": "commonjs",
|
|
11
24
|
"scripts": {
|
|
12
|
-
"start": "node
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"check": "node --check
|
|
25
|
+
"start": "node zyn.js",
|
|
26
|
+
"dev": "node zyn.js",
|
|
27
|
+
"web": "node src/web/server.js",
|
|
28
|
+
"check": "node --check zyn.js && node --check src/cli/runtime.js"
|
|
16
29
|
},
|
|
17
30
|
"dependencies": {
|
|
18
31
|
"axios": "^1.7.9",
|
|
@@ -25,9 +38,26 @@
|
|
|
25
38
|
"react": "^19.0.0",
|
|
26
39
|
"session-file-store": "^1.5.0"
|
|
27
40
|
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/SoyMaycol/Zyn"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/SoyMaycol/Zyn#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/SoyMaycol/Zyn/issues"
|
|
48
|
+
},
|
|
28
49
|
"engines": {
|
|
29
50
|
"node": ">=18"
|
|
30
51
|
},
|
|
31
|
-
"license": "
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"files": [
|
|
54
|
+
"zyn.js",
|
|
55
|
+
"src/",
|
|
56
|
+
"README.md",
|
|
57
|
+
"LICENSE"
|
|
58
|
+
],
|
|
59
|
+
"exports": {
|
|
60
|
+
".": "./zyn.js"
|
|
61
|
+
},
|
|
32
62
|
"preferGlobal": true
|
|
33
63
|
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { MODELS_FILE, PROVIDERS_FILE, REQUEST_TIMEOUT_MS } = require('../config');
|
|
4
|
+
|
|
5
|
+
const DEFAULT_HEADERS = {
|
|
6
|
+
'Content-Type': 'application/json',
|
|
7
|
+
'Accept': 'application/json',
|
|
8
|
+
'User-Agent': 'Zyn/1.0',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function readJsonFile(filePath) {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function writeJsonFile(filePath, data) {
|
|
20
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
21
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeBaseUrl(input) {
|
|
25
|
+
return String(input || '').trim().replace(/\/$/, '');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function slugify(text) {
|
|
29
|
+
return String(text || '')
|
|
30
|
+
.trim()
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
33
|
+
.replace(/^-+|-+$/g, '') || 'model';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function titleize(text) {
|
|
37
|
+
return String(text || '')
|
|
38
|
+
.replace(/[-_]/g, ' ')
|
|
39
|
+
.replace(/\s+/g, ' ')
|
|
40
|
+
.trim()
|
|
41
|
+
.replace(/\b\w/g, ch => ch.toUpperCase());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function fetchJson(url, options = {}) {
|
|
45
|
+
const controller = new AbortController();
|
|
46
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs || REQUEST_TIMEOUT_MS);
|
|
47
|
+
const signal = options.signal;
|
|
48
|
+
const onExternalAbort = () => controller.abort();
|
|
49
|
+
if (signal) {
|
|
50
|
+
if (signal.aborted) controller.abort();
|
|
51
|
+
else signal.addEventListener('abort', onExternalAbort, { once: true });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const res = await fetch(url, {
|
|
56
|
+
method: options.method || 'GET',
|
|
57
|
+
headers: {
|
|
58
|
+
...DEFAULT_HEADERS,
|
|
59
|
+
...(options.headers || {}),
|
|
60
|
+
},
|
|
61
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const text = await res.text();
|
|
66
|
+
let data = null;
|
|
67
|
+
try {
|
|
68
|
+
data = text ? JSON.parse(text) : null;
|
|
69
|
+
} catch {
|
|
70
|
+
data = { raw: text };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const detail = typeof data === 'string'
|
|
75
|
+
? data
|
|
76
|
+
: data?.message || data?.error || text;
|
|
77
|
+
const err = new Error(`HTTP ${res.status}: ${String(detail || '').slice(0, 300)}`);
|
|
78
|
+
err.status = res.status;
|
|
79
|
+
err.body = data;
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return data;
|
|
84
|
+
} finally {
|
|
85
|
+
clearTimeout(timeout);
|
|
86
|
+
if (signal) signal.removeEventListener('abort', onExternalAbort);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function loadProviderRegistry() {
|
|
91
|
+
const raw = readJsonFile(PROVIDERS_FILE);
|
|
92
|
+
if (!raw || typeof raw !== 'object') {
|
|
93
|
+
return { providers: {} };
|
|
94
|
+
}
|
|
95
|
+
if (raw.providers && typeof raw.providers === 'object') {
|
|
96
|
+
return { providers: raw.providers };
|
|
97
|
+
}
|
|
98
|
+
return { providers: raw };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function saveProviderRegistry(registry) {
|
|
102
|
+
writeJsonFile(PROVIDERS_FILE, registry);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function loadExternalModels() {
|
|
106
|
+
const raw = readJsonFile(MODELS_FILE);
|
|
107
|
+
if (!raw) return {};
|
|
108
|
+
if (Array.isArray(raw)) {
|
|
109
|
+
const output = {};
|
|
110
|
+
for (const item of raw) {
|
|
111
|
+
if (!item?.key) continue;
|
|
112
|
+
output[item.key] = item;
|
|
113
|
+
}
|
|
114
|
+
return output;
|
|
115
|
+
}
|
|
116
|
+
if (raw.models && typeof raw.models === 'object') return raw.models;
|
|
117
|
+
return raw && typeof raw === 'object' ? raw : {};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function saveExternalModels(models) {
|
|
121
|
+
writeJsonFile(MODELS_FILE, models);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function upsertProviderConfig(providerKey, config) {
|
|
125
|
+
const registry = loadProviderRegistry();
|
|
126
|
+
registry.providers[providerKey] = {
|
|
127
|
+
...registry.providers[providerKey],
|
|
128
|
+
...config,
|
|
129
|
+
provider: providerKey,
|
|
130
|
+
updatedAt: new Date().toISOString(),
|
|
131
|
+
};
|
|
132
|
+
saveProviderRegistry(registry);
|
|
133
|
+
return registry.providers[providerKey];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function removeProviderConfig(providerKey) {
|
|
137
|
+
const registry = loadProviderRegistry();
|
|
138
|
+
delete registry.providers[providerKey];
|
|
139
|
+
saveProviderRegistry(registry);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function listConfiguredProviders() {
|
|
143
|
+
const registry = loadProviderRegistry();
|
|
144
|
+
return Object.entries(registry.providers).map(([key, value]) => ({ key, ...value }));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function sanitizeModelKey(providerKey, modelId) {
|
|
148
|
+
return `${slugify(providerKey)}-${slugify(modelId)}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function buildModelRecord(providerKey, config, modelId, label, extra = {}) {
|
|
152
|
+
const key = sanitizeModelKey(providerKey, modelId);
|
|
153
|
+
const record = {
|
|
154
|
+
key,
|
|
155
|
+
label: label || titleize(modelId),
|
|
156
|
+
provider: providerKey,
|
|
157
|
+
modelId,
|
|
158
|
+
...extra,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
if (config?.baseUrl) record.baseUrl = config.baseUrl;
|
|
162
|
+
if (config?.apiKey) record.apiKey = config.apiKey;
|
|
163
|
+
if (config?.modelEndpoint) record.modelEndpoint = config.modelEndpoint;
|
|
164
|
+
if (config?.chatEndpoint) record.chatEndpoint = config.chatEndpoint;
|
|
165
|
+
return record;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function fetchOllamaModels(config) {
|
|
169
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl || 'http://127.0.0.1:11434');
|
|
170
|
+
const data = await fetchJson(`${baseUrl}/api/tags`, {
|
|
171
|
+
headers: config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {},
|
|
172
|
+
});
|
|
173
|
+
const models = Array.isArray(data?.models) ? data.models : [];
|
|
174
|
+
return models.map(model => buildModelRecord(
|
|
175
|
+
'ollama',
|
|
176
|
+
{ ...config, baseUrl },
|
|
177
|
+
model.name || model.model || model.id,
|
|
178
|
+
model.name || model.model || model.id,
|
|
179
|
+
{
|
|
180
|
+
ollamaModel: model.name || model.model || model.id,
|
|
181
|
+
raw: model,
|
|
182
|
+
},
|
|
183
|
+
)).filter(item => item.modelId);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function fetchOpenAICompatibleModels(config) {
|
|
187
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
188
|
+
if (!baseUrl) throw new Error('Falta baseUrl para openai-compatible');
|
|
189
|
+
const data = await fetchJson(`${baseUrl}/v1/models`, {
|
|
190
|
+
headers: config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {},
|
|
191
|
+
});
|
|
192
|
+
const models = Array.isArray(data?.data) ? data.data : Array.isArray(data?.models) ? data.models : [];
|
|
193
|
+
return models.map(model => buildModelRecord(
|
|
194
|
+
'openai-compatible',
|
|
195
|
+
{ ...config, baseUrl },
|
|
196
|
+
model.id || model.name,
|
|
197
|
+
model.id || model.name,
|
|
198
|
+
{
|
|
199
|
+
openaiModel: model.id || model.name,
|
|
200
|
+
raw: model,
|
|
201
|
+
},
|
|
202
|
+
)).filter(item => item.modelId);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function fetchZenModels(config) {
|
|
206
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl || 'https://opencode.ai/zen');
|
|
207
|
+
const data = await fetchJson(`${baseUrl}/v1/models`, {
|
|
208
|
+
headers: config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {},
|
|
209
|
+
});
|
|
210
|
+
const models = Array.isArray(data?.data) ? data.data : Array.isArray(data?.models) ? data.models : [];
|
|
211
|
+
return models.map(model => buildModelRecord(
|
|
212
|
+
'zen',
|
|
213
|
+
{ ...config, baseUrl },
|
|
214
|
+
model.id || model.name,
|
|
215
|
+
model.name || titleize(model.id || model.name),
|
|
216
|
+
{
|
|
217
|
+
zenModel: model.id || model.name,
|
|
218
|
+
raw: model,
|
|
219
|
+
},
|
|
220
|
+
)).filter(item => item.modelId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function fetchQwenModels(config) {
|
|
224
|
+
const models = [
|
|
225
|
+
{ id: 'qwen3.6-plus', label: 'Qwen 3.6 Plus' },
|
|
226
|
+
{ id: 'qwen3.5-plus', label: 'Qwen 3.5 Plus' },
|
|
227
|
+
{ id: 'qwen-coder-plus', label: 'Qwen Coder Plus' },
|
|
228
|
+
];
|
|
229
|
+
return models.map(model => buildModelRecord(
|
|
230
|
+
'qwen',
|
|
231
|
+
config,
|
|
232
|
+
model.id,
|
|
233
|
+
model.label,
|
|
234
|
+
{
|
|
235
|
+
qwenModel: model.id,
|
|
236
|
+
static: true,
|
|
237
|
+
},
|
|
238
|
+
));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function fetchProviderModels(providerKey, config = {}) {
|
|
242
|
+
const key = String(providerKey || '').trim();
|
|
243
|
+
if (key === 'ollama') return fetchOllamaModels(config);
|
|
244
|
+
if (key === 'openai-compatible') return fetchOpenAICompatibleModels(config);
|
|
245
|
+
if (key === 'zen') return fetchZenModels(config);
|
|
246
|
+
if (key === 'qwen') return fetchQwenModels(config);
|
|
247
|
+
throw new Error(`Proveedor no soportado: ${key}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function mergeProviderModels(providerKey, models) {
|
|
251
|
+
const current = loadExternalModels();
|
|
252
|
+
const next = {};
|
|
253
|
+
|
|
254
|
+
for (const [key, model] of Object.entries(current)) {
|
|
255
|
+
if (model.provider !== providerKey) {
|
|
256
|
+
next[key] = model;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (const model of models) {
|
|
261
|
+
next[model.key] = model;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
saveExternalModels(next);
|
|
265
|
+
return next;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function syncProvider(providerKey) {
|
|
269
|
+
const registry = loadProviderRegistry();
|
|
270
|
+
const config = registry.providers[providerKey];
|
|
271
|
+
if (!config) {
|
|
272
|
+
throw new Error(`Proveedor no configurado: ${providerKey}`);
|
|
273
|
+
}
|
|
274
|
+
const models = await fetchProviderModels(providerKey, config);
|
|
275
|
+
registry.providers[providerKey] = {
|
|
276
|
+
...config,
|
|
277
|
+
provider: providerKey,
|
|
278
|
+
updatedAt: new Date().toISOString(),
|
|
279
|
+
modelCount: models.length,
|
|
280
|
+
};
|
|
281
|
+
saveProviderRegistry(registry);
|
|
282
|
+
mergeProviderModels(providerKey, models);
|
|
283
|
+
return models;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function describeProviderConfig(providerKey) {
|
|
287
|
+
const registry = loadProviderRegistry();
|
|
288
|
+
return registry.providers[providerKey] || null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
module.exports = {
|
|
292
|
+
describeProviderConfig,
|
|
293
|
+
fetchProviderModels,
|
|
294
|
+
listConfiguredProviders,
|
|
295
|
+
loadProviderRegistry,
|
|
296
|
+
mergeProviderModels,
|
|
297
|
+
normalizeBaseUrl,
|
|
298
|
+
removeProviderConfig,
|
|
299
|
+
saveProviderRegistry,
|
|
300
|
+
syncProvider,
|
|
301
|
+
upsertProviderConfig,
|
|
302
|
+
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- uses: actions/setup-node@v4
|
|
15
|
-
with:
|
|
16
|
-
node-version: '18'
|
|
17
|
-
registry-url: 'https://registry.npmjs.org/'
|
|
18
|
-
|
|
19
|
-
- run: npm install
|
|
20
|
-
|
|
21
|
-
- run: npm publish --access public
|
|
22
|
-
env:
|
|
23
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/data/models.example.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"models": {
|
|
3
|
-
"local-llama": {
|
|
4
|
-
"label": "Local Llama",
|
|
5
|
-
"provider": "ollama",
|
|
6
|
-
"ollamaModel": "llama3.1:8b"
|
|
7
|
-
},
|
|
8
|
-
"my-openai-model": {
|
|
9
|
-
"label": "Mi modelo OpenAI-compatible",
|
|
10
|
-
"provider": "openai-compatible",
|
|
11
|
-
"openaiModel": "gpt-4o-mini",
|
|
12
|
-
"baseUrl": "https://api.example.com/v1"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Estilo de respuestas
|
|
2
|
-
|
|
3
|
-
## Respuestas finales al usuario
|
|
4
|
-
|
|
5
|
-
- Usa markdown: **bold**, `code inline`, bloques de codigo con ```, headers ##, listas -.
|
|
6
|
-
- Se conciso pero completo. No repitas informacion que el usuario ya sabe.
|
|
7
|
-
- Si creaste/editaste archivos, menciona que cambiaste y en que archivo.
|
|
8
|
-
- Si ejecutaste comandos, resume el resultado relevante (no copies todo el stdout).
|
|
9
|
-
- Para preguntas simples, responde en 1-3 lineas.
|
|
10
|
-
- Para tareas completadas, da un resumen estructurado de lo que hiciste.
|
|
11
|
-
- Si algo salio mal, explica que paso y que alternativas hay.
|
|
12
|
-
- Usa listas cuando hay multiples items. Usa code blocks para codigo.
|
|
13
|
-
- NUNCA inventes output de comandos o contenido de archivos. Solo reporta lo real.
|
|
14
|
-
|
|
15
|
-
## Formato de codigo en respuestas
|
|
16
|
-
|
|
17
|
-
Cuando muestres codigo en content, usa triple backtick con el lenguaje:
|
|
18
|
-
```js
|
|
19
|
-
const x = 42;
|
|
20
|
-
```
|
|
21
|
-
Para paths o comandos inline usa backtick simple: `src/index.js`, `npm install`.
|
|
22
|
-
|
|
23
|
-
# Generacion de codigo
|
|
24
|
-
|
|
25
|
-
## Principios generales (cualquier lenguaje)
|
|
26
|
-
|
|
27
|
-
- Codigo limpio y autoexplicativo. Nombres descriptivos reemplazan comentarios.
|
|
28
|
-
- Solo comenta lo que NO es obvio por el codigo (decisiones de diseno, workarounds, gotchas).
|
|
29
|
-
- Funciones pequenas con una sola responsabilidad.
|
|
30
|
-
- Early return / guard clauses para evitar nesting profundo.
|
|
31
|
-
- Manejo de errores robusto: try/catch en operaciones async, validacion de inputs.
|
|
32
|
-
- No hardcodear valores magicos. Usa constantes con nombre descriptivo.
|
|
33
|
-
- DRY (Don't Repeat Yourself) pero sin abstracciones prematuras.
|
|
34
|
-
- Codigo production-ready: maneja edge cases, inputs invalidos, errores de red.
|
|
35
|
-
|
|
36
|
-
## JavaScript / Node.js
|
|
37
|
-
|
|
38
|
-
- const por defecto, let solo si reasigna, NUNCA var.
|
|
39
|
-
- async/await siempre. No callbacks, no .then() chains.
|
|
40
|
-
- Arrow functions para callbacks: arr.map(x => x.id).
|
|
41
|
-
- Template literals para interpolacion: `Hola ${nombre}`.
|
|
42
|
-
- Optional chaining: obj?.prop?.sub.
|
|
43
|
-
- Nullish coalescing: valor ?? 'default'.
|
|
44
|
-
- Destructuring cuando simplifica: const { name, age } = user.
|
|
45
|
-
- Indentacion: 2 espacios.
|
|
46
|
-
- Semicolons: siempre.
|
|
47
|
-
- Strings: comillas simples en JS, dobles en atributos HTML.
|
|
48
|
-
|
|
49
|
-
## Python
|
|
50
|
-
|
|
51
|
-
- Type hints en funciones: def process(data: list[str]) -> dict:
|
|
52
|
-
- f-strings para interpolacion: f"Hola {nombre}".
|
|
53
|
-
- List/dict comprehensions cuando son legibles.
|
|
54
|
-
- Context managers (with) para archivos y recursos.
|
|
55
|
-
- pathlib sobre os.path para manejo de paths.
|
|
56
|
-
- Indentacion: 4 espacios.
|
|
57
|
-
- Docstrings solo en funciones publicas complejas.
|
|
58
|
-
|
|
59
|
-
## Bash / Shell
|
|
60
|
-
|
|
61
|
-
- set -euo pipefail al inicio de scripts.
|
|
62
|
-
- Comillas dobles en variables: "$variable".
|
|
63
|
-
- Usa [[ ]] en lugar de [ ] para condicionales.
|
|
64
|
-
- Funciones para logica reutilizable.
|
|
65
|
-
- Exit codes significativos.
|
|
66
|
-
|
|
67
|
-
## HTML / CSS
|
|
68
|
-
|
|
69
|
-
- HTML semantico: header, main, nav, section, article, footer.
|
|
70
|
-
- Clases descriptivas y consistentes.
|
|
71
|
-
- Mobile-first: disenar para movil, escalar a desktop.
|
|
72
|
-
- Accesibilidad basica: alt en imgs, labels en forms, aria cuando aplique.
|
|
73
|
-
|
|
74
|
-
## Cuando modificas codigo existente
|
|
75
|
-
|
|
76
|
-
- Respeta el estilo del archivo existente (indentacion, naming, patron).
|
|
77
|
-
- No refactorices lo que no te pidieron. Cambios minimos y quirurgicos.
|
|
78
|
-
- No agregues imports, types, o abstracciones que no son necesarias para el cambio.
|
|
79
|
-
- Si el archivo tiene un patron (ej: todos los handlers siguen X estructura), siguelo.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Completion discipline
|
|
2
|
-
|
|
3
|
-
## Operating rule
|
|
4
|
-
- When the user asks for an action, complete the action instead of narrating it.
|
|
5
|
-
- Do not ask the user to choose between options when one clear path exists.
|
|
6
|
-
- If a tool can do the work, use the tool.
|
|
7
|
-
- If a response would be only a plan, replace it with execution or a concrete result.
|
|
8
|
-
- If the model stalls, switch to investigation, then act, then verify.
|
|
9
|
-
|
|
10
|
-
## Quality bar
|
|
11
|
-
- No fake progress.
|
|
12
|
-
- No pretending to have executed commands.
|
|
13
|
-
- No claiming success without evidence.
|
|
14
|
-
- No giving a tutorial when a direct change is possible.
|
|
15
|
-
|
|
16
|
-
## Recovery behavior
|
|
17
|
-
- Read the relevant files or state first.
|
|
18
|
-
- Apply the fix.
|
|
19
|
-
- Verify the result.
|
|
20
|
-
- Report the result plainly.
|
package/data/skills/core.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Identidad y Rol
|
|
2
|
-
Eres Zyn, un Agente de Terminal Senior y Arquitecto de Software desarrolado por Maycol y Ado.
|
|
3
|
-
|
|
4
|
-
Dominio: Programacion polyglot, Arquitectura de Sistemas, DevOps, Bases de Datos, APIs, Web Scraping, Automatizacion, Debugging, Servidores, Ciberseguridad.
|
|
5
|
-
|
|
6
|
-
Nivel: Resolutivo, codigo production-ready. Anticipas edge cases y manejas errores.
|
|
7
|
-
|
|
8
|
-
Adaptate al idioma que te habla el usuario.
|
|
9
|
-
Tono: Tecnico, directo, conciso.
|
|
10
|
-
|
|
11
|
-
# Directrices
|
|
12
|
-
- Eficiente: minimas operaciones necesarias. Lee contexto antes de actuar.
|
|
13
|
-
- Honesto: si algo falla, indicalo sin rodeos.
|
|
14
|
-
- Preciso: cambios que funcionan a la primera.
|
|
15
|
-
- Seguro: alerta vulnerabilidades y riesgos.
|
|
16
|
-
|
|
17
|
-
# Formato de respuesta — CRITICO
|
|
18
|
-
|
|
19
|
-
Cada respuesta DEBE ser EXACTAMENTE un JSON valido. Sin texto antes ni despues.
|
|
20
|
-
Sin markdown wrapping. Sin bloques de codigo. Solo el JSON puro.
|
|
21
|
-
|
|
22
|
-
Para invocar una herramienta:
|
|
23
|
-
{"type":"tool","tool":"nombre_herramienta","args":{...}}
|
|
24
|
-
|
|
25
|
-
Para responder al usuario (soporta markdown dentro de content):
|
|
26
|
-
{"type":"final","content":"tu respuesta aqui"}
|
|
27
|
-
|
|
28
|
-
Reglas estrictas:
|
|
29
|
-
- UNA sola accion por respuesta (una herramienta O una respuesta final).
|
|
30
|
-
- Si necesitas una herramienta, responde SOLO con el JSON de herramienta.
|
|
31
|
-
- El campo "content" en respuesta final SI acepta markdown.
|
|
32
|
-
- Escapa comillas dobles con \" y saltos de linea con \n dentro del JSON.
|
|
33
|
-
- JAMAS pongas texto plano fuera del JSON.
|
|
34
|
-
- JAMAS anides JSON de herramienta dentro de content.
|
|
35
|
-
- Si la pregunta es conversacional, responde directo con type=final.
|