trackops 1.0.1 → 2.0.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 (83) hide show
  1. package/README.md +292 -272
  2. package/bin/trackops.js +108 -50
  3. package/lib/config.js +267 -38
  4. package/lib/control.js +534 -480
  5. package/lib/env.js +244 -0
  6. package/lib/i18n.js +61 -53
  7. package/lib/init.js +170 -47
  8. package/lib/locale.js +63 -0
  9. package/lib/opera-bootstrap.js +1075 -0
  10. package/lib/opera.js +524 -125
  11. package/lib/preferences.js +74 -0
  12. package/lib/registry.js +27 -13
  13. package/lib/release.js +56 -0
  14. package/lib/resources.js +42 -0
  15. package/lib/runtime-state.js +144 -0
  16. package/lib/server.js +1004 -521
  17. package/lib/skills.js +148 -124
  18. package/lib/workspace.js +260 -0
  19. package/locales/en.json +418 -132
  20. package/locales/es.json +418 -132
  21. package/package.json +8 -9
  22. package/scripts/postinstall-locale.js +21 -0
  23. package/scripts/skills-marketplace-smoke.js +124 -0
  24. package/scripts/smoke-tests.js +570 -0
  25. package/scripts/sync-skill-version.js +21 -0
  26. package/scripts/validate-skill.js +89 -0
  27. package/skills/trackops/SKILL.md +89 -0
  28. package/skills/trackops/agents/openai.yaml +3 -0
  29. package/skills/trackops/references/activation.md +73 -0
  30. package/skills/trackops/references/troubleshooting.md +49 -0
  31. package/skills/trackops/references/workflow.md +26 -0
  32. package/skills/trackops/scripts/bootstrap-trackops.js +203 -0
  33. package/skills/trackops/skill.json +29 -0
  34. package/templates/opera/agent.md +10 -9
  35. package/templates/opera/architecture/dependency-graph.md +24 -0
  36. package/templates/opera/architecture/runtime-automation.md +24 -0
  37. package/templates/opera/architecture/runtime-operations.md +34 -0
  38. package/templates/opera/en/agent.md +27 -0
  39. package/templates/opera/en/architecture/dependency-graph.md +24 -0
  40. package/templates/opera/en/architecture/runtime-automation.md +24 -0
  41. package/templates/opera/en/architecture/runtime-operations.md +34 -0
  42. package/templates/opera/en/genesis.md +79 -0
  43. package/templates/opera/en/references/autonomy-and-recovery.md +23 -0
  44. package/templates/opera/en/references/opera-cycle.md +62 -0
  45. package/templates/opera/en/registry.md +28 -0
  46. package/templates/opera/en/reviews/delivery-audit.md +18 -0
  47. package/templates/opera/en/reviews/integration-audit.md +18 -0
  48. package/templates/opera/en/router.md +49 -0
  49. package/templates/opera/genesis.md +79 -94
  50. package/templates/opera/reviews/delivery-audit.md +18 -0
  51. package/templates/opera/reviews/integration-audit.md +18 -0
  52. package/templates/opera/router.md +15 -5
  53. package/templates/skills/changelog-updater/locales/en/SKILL.md +11 -0
  54. package/templates/skills/commiter/locales/en/SKILL.md +11 -0
  55. package/templates/skills/opera-contract-auditor/SKILL.md +38 -0
  56. package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -0
  57. package/templates/skills/opera-policy-guard/SKILL.md +26 -0
  58. package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -0
  59. package/templates/skills/project-starter-skill/SKILL.md +89 -164
  60. package/templates/skills/project-starter-skill/locales/en/SKILL.md +104 -0
  61. package/ui/css/panels.css +956 -953
  62. package/ui/index.html +1 -1
  63. package/ui/js/api.js +211 -194
  64. package/ui/js/app.js +200 -199
  65. package/ui/js/i18n.js +14 -0
  66. package/ui/js/onboarding.js +439 -437
  67. package/ui/js/state.js +130 -129
  68. package/ui/js/utils.js +175 -172
  69. package/ui/js/views/board.js +255 -254
  70. package/ui/js/views/execution.js +256 -256
  71. package/ui/js/views/insights.js +340 -339
  72. package/ui/js/views/overview.js +366 -361
  73. package/ui/js/views/settings.js +340 -202
  74. package/ui/js/views/sidebar.js +131 -132
  75. package/ui/js/views/skills.js +163 -162
  76. package/ui/js/views/tasks.js +406 -405
  77. package/ui/js/views/topbar.js +239 -183
  78. package/templates/etapa/agent.md +0 -26
  79. package/templates/etapa/genesis.md +0 -94
  80. package/templates/etapa/references/autonomy-and-recovery.md +0 -117
  81. package/templates/etapa/references/etapa-cycle.md +0 -193
  82. package/templates/etapa/registry.md +0 -28
  83. package/templates/etapa/router.md +0 -39
@@ -1,183 +1,239 @@
1
- /**
2
- * topbar.js — Barra superior del dashboard
3
- */
4
-
5
- import { icon } from '../icons.js';
6
- import * as state from '../state.js';
7
- import * as api from '../api.js';
8
- import { flash } from './flash.js';
9
- import { esc, debounce } from '../utils.js';
10
- import * as theme from '../theme.js';
11
-
12
- /** Renderiza el topbar */
13
- export function render() {
14
- const el = document.getElementById('topbar');
15
- if (!el) return;
16
-
17
- const payload = state.getPayload();
18
- const projects = state.get('projects');
19
- const currentId = state.get('currentProjectId');
20
- const runtime = payload?.runtime;
21
-
22
- el.innerHTML = `
23
- <div class="topbar">
24
- <!-- Hamburger (mobile) -->
25
- <button class="topbar-hamburger" type="button" id="sidebar-toggle" aria-label="Abrir menú" aria-expanded="false" aria-controls="sidebar">
26
- <span></span><span></span><span></span>
27
- </button>
28
-
29
- <!-- Search -->
30
- <div class="topbar-search">
31
- <div class="search-wrapper" role="search">
32
- <span class="search-icon" aria-hidden="true">${icon('search', 16)}</span>
33
- <input
34
- type="search"
35
- id="global-search"
36
- aria-label="Buscar tareas"
37
- placeholder="Buscar tareas…"
38
- autocomplete="off"
39
- value="${esc(state.get('searchQuery'))}"
40
- />
41
- <span class="search-kbd" aria-hidden="true">⌘F</span>
42
- </div>
43
- </div>
44
-
45
- <!-- Derecha -->
46
- <div class="topbar-right">
47
-
48
- <!-- Timer activo -->
49
- <div class="topbar-timer" id="topbar-timer" aria-label="Seguimiento de tiempo" aria-live="polite">
50
- <span class="topbar-timer-dot" aria-hidden="true"></span>
51
- <span id="topbar-timer-display">00:00:00</span>
52
- </div>
53
-
54
- <!-- Repo status -->
55
- ${runtime ? _renderRepoBadge(runtime) : ''}
56
-
57
- <!-- Project selector -->
58
- ${projects.length > 0 ? _renderProjectSelector(projects, currentId) : ''}
59
-
60
- <!-- Sync button -->
61
- <button class="btn btn-ghost btn-sm" id="sync-btn" type="button" aria-label="Sincronizar documentación">
62
- ${icon('sync', 16)} Sincronizar
63
- </button>
64
-
65
- <!-- Theme toggle -->
66
- ${theme.renderButton()}
67
-
68
- <!-- Refresh -->
69
- <button class="btn btn-ghost btn-sm btn-icon" id="refresh-btn" type="button" aria-label="Refrescar estado">
70
- ${icon('refresh', 16)}
71
- </button>
72
-
73
- </div>
74
- </div>
75
- `;
76
-
77
- _bindEvents();
78
- }
79
-
80
- function _renderRepoBadge(runtime) {
81
- const isClean = runtime.clean;
82
- const label = isClean ? 'Repo limpio' : `${runtime.staged}s ${runtime.unstaged}u ${runtime.untracked}?`;
83
- return `
84
- <div class="repo-badge ${isClean ? 'clean' : 'dirty'}" title="${esc(runtime.branch || '')}">
85
- <span class="repo-badge-dot" aria-hidden="true"></span>
86
- <span>${icon('gitBranch', 12)} ${esc(runtime.branch || 'sin rama')} · ${label}</span>
87
- </div>
88
- `;
89
- }
90
-
91
- function _renderProjectSelector(projects, currentId) {
92
- const options = projects.map(p =>
93
- `<option value="${esc(p.id)}" ${p.id === currentId ? 'selected' : ''} ${p.available ? '' : 'disabled'}>
94
- ${esc(p.name)}${p.available ? '' : ' (no disponible)'}
95
- </option>`
96
- ).join('');
97
-
98
- return `
99
- <div class="project-select-wrapper" title="Proyecto activo">
100
- <select id="project-select" aria-label="Seleccionar proyecto activo">
101
- ${options}
102
- </select>
103
- </div>
104
- `;
105
- }
106
-
107
- function _bindEvents() {
108
- // Hamburger → sidebar open
109
- document.getElementById('sidebar-toggle')?.addEventListener('click', () => {
110
- const sidebar = document.getElementById('sidebar');
111
- const isOpen = sidebar?.classList.toggle('is-open');
112
- document.getElementById('sidebar-toggle')?.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
113
- });
114
-
115
- // Theme toggle
116
- theme.bindButton();
117
-
118
- // Cerrar sidebar al hacer clic fuera (mobile)
119
- document.addEventListener('click', e => {
120
- const sidebar = document.getElementById('sidebar');
121
- const toggle = document.getElementById('sidebar-toggle');
122
- if (sidebar?.classList.contains('is-open') &&
123
- !sidebar.contains(e.target) && !toggle?.contains(e.target)) {
124
- sidebar.classList.remove('is-open');
125
- toggle?.setAttribute('aria-expanded', 'false');
126
- }
127
- });
128
-
129
- // Project selector
130
- document.getElementById('project-select')?.addEventListener('change', async e => {
131
- const id = e.target.value;
132
- state.update('currentProjectId', id);
133
- localStorage.setItem('ops-dashboard-project', id);
134
- state.update('selectedTaskId', null);
135
- // Trigger refresh global
136
- window.dispatchEvent(new CustomEvent('ops:refresh'));
137
- });
138
-
139
- // Sync button
140
- document.getElementById('sync-btn')?.addEventListener('click', async () => {
141
- const btn = document.getElementById('sync-btn');
142
- if (btn) { btn.disabled = true; btn.innerHTML = `${icon('sync', 16)} Sincronizando…`; }
143
- try {
144
- await api.syncDocs();
145
- flash('Documentación sincronizada.', 'success');
146
- window.dispatchEvent(new CustomEvent('ops:refresh'));
147
- } catch (err) {
148
- flash(err.message, 'error');
149
- } finally {
150
- if (btn) { btn.disabled = false; btn.innerHTML = `${icon('sync', 16)} Sincronizar`; }
151
- }
152
- });
153
-
154
- // Refresh button
155
- document.getElementById('refresh-btn')?.addEventListener('click', () => {
156
- window.dispatchEvent(new CustomEvent('ops:refresh'));
157
- });
158
-
159
- // Búsqueda global (debounced)
160
- const searchInput = document.getElementById('global-search');
161
- if (searchInput) {
162
- const handleSearch = debounce(e => {
163
- state.update('searchQuery', e.target.value);
164
- window.dispatchEvent(new CustomEvent('ops:search', { detail: { query: e.target.value } }));
165
- }, 250);
166
- searchInput.addEventListener('input', handleSearch);
167
-
168
- // Atajo de teclado ⌘/Ctrl+F
169
- document.addEventListener('keydown', e => {
170
- if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
171
- e.preventDefault();
172
- searchInput.focus();
173
- searchInput.select();
174
- }
175
- });
176
- }
177
- }
178
-
179
- /** Actualiza solo el timer del topbar sin re-renderizar */
180
- export function updateTimer(display) {
181
- const el = document.getElementById('topbar-timer-display');
182
- if (el) el.textContent = display;
183
- }
1
+ /**
2
+ * topbar.js — Barra superior del dashboard
3
+ */
4
+
5
+ import { icon } from '../icons.js';
6
+ import * as state from '../state.js';
7
+ import * as api from '../api.js';
8
+ import { flash } from './flash.js';
9
+ import { esc, debounce } from '../utils.js';
10
+ import * as theme from '../theme.js';
11
+ import { t } from '../i18n.js';
12
+
13
+ /** Renderiza el topbar */
14
+ export function render() {
15
+ const el = document.getElementById('topbar');
16
+ if (!el) return;
17
+
18
+ const payload = state.getPayload();
19
+ const projects = state.get('projects');
20
+ const currentId = state.get('currentProjectId');
21
+ const currentLocale = state.get('locale') || payload?.i18n?.locale || 'es';
22
+ const runtime = payload?.runtime;
23
+
24
+ el.innerHTML = `
25
+ <div class="topbar">
26
+ <!-- Hamburger (mobile) -->
27
+ <button class="topbar-hamburger" type="button" id="sidebar-toggle" aria-label="${t('ui.topbar.openMenu', {}, 'Open menu')}" aria-expanded="false" aria-controls="sidebar">
28
+ <span></span><span></span><span></span>
29
+ </button>
30
+
31
+ <!-- Search -->
32
+ <div class="topbar-search">
33
+ <div class="search-wrapper" role="search">
34
+ <span class="search-icon" aria-hidden="true">${icon('search', 16)}</span>
35
+ <input
36
+ type="search"
37
+ id="global-search"
38
+ aria-label="${t('ui.topbar.searchAria', {}, 'Search tasks')}"
39
+ placeholder="${t('ui.topbar.searchPlaceholder', {}, 'Search tasks…')}"
40
+ autocomplete="off"
41
+ value="${esc(state.get('searchQuery'))}"
42
+ />
43
+ <span class="search-kbd" aria-hidden="true">⌘F</span>
44
+ </div>
45
+ </div>
46
+
47
+ <!-- Derecha -->
48
+ <div class="topbar-right">
49
+
50
+ <!-- Timer activo -->
51
+ <div class="topbar-timer" id="topbar-timer" aria-label="${t('ui.topbar.timer', {}, 'Time tracking')}" aria-live="polite">
52
+ <span class="topbar-timer-dot" aria-hidden="true"></span>
53
+ <span id="topbar-timer-display">00:00:00</span>
54
+ </div>
55
+
56
+ <!-- Repo status -->
57
+ ${runtime ? _renderRepoBadge(runtime) : ''}
58
+
59
+ <!-- Project selector -->
60
+ ${projects.length > 0 ? _renderProjectSelector(projects, currentId) : ''}
61
+
62
+ <!-- Locale selector -->
63
+ ${_renderLocaleSelector(currentLocale)}
64
+
65
+ <!-- Sync button -->
66
+ <button class="btn btn-ghost btn-sm" id="sync-btn" type="button" aria-label="${t('ui.topbar.syncAria', {}, 'Sync documentation')}">
67
+ ${icon('sync', 16)} ${t('ui.topbar.sync', {}, 'Sync')}
68
+ </button>
69
+
70
+ <!-- Theme toggle -->
71
+ ${theme.renderButton()}
72
+
73
+ <!-- Refresh -->
74
+ <button class="btn btn-ghost btn-sm btn-icon" id="refresh-btn" type="button" aria-label="${t('ui.topbar.refresh', {}, 'Refresh state')}">
75
+ ${icon('refresh', 16)}
76
+ </button>
77
+
78
+ </div>
79
+ </div>
80
+ `;
81
+
82
+ _bindEvents();
83
+ }
84
+
85
+ function _renderRepoBadge(runtime) {
86
+ const isClean = runtime.clean;
87
+ const label = isClean
88
+ ? t('ui.topbar.repoClean', {}, 'Clean repo')
89
+ : t('ui.topbar.repoDirty', {
90
+ staged: runtime.staged,
91
+ unstaged: runtime.unstaged,
92
+ untracked: runtime.untracked,
93
+ }, `${runtime.staged}s ${runtime.unstaged}u ${runtime.untracked}?`);
94
+ return `
95
+ <div class="repo-badge ${isClean ? 'clean' : 'dirty'}" title="${esc(runtime.branch || '')}">
96
+ <span class="repo-badge-dot" aria-hidden="true"></span>
97
+ <span>${icon('gitBranch', 12)} ${esc(runtime.branch || t('ui.topbar.noBranch', {}, 'no branch'))} · ${label}</span>
98
+ </div>
99
+ `;
100
+ }
101
+
102
+ function _renderProjectSelector(projects, currentId) {
103
+ const options = projects.map(p =>
104
+ `<option value="${esc(p.id)}" ${p.id === currentId ? 'selected' : ''} ${p.available ? '' : 'disabled'}>
105
+ ${esc(p.name)}${p.available ? '' : ` (${t('ui.topbar.unavailable', {}, 'unavailable')})`}
106
+ </option>`
107
+ ).join('');
108
+
109
+ return `
110
+ <div class="project-select-wrapper" title="${t('ui.topbar.activeProject', {}, 'Active project')}">
111
+ <select id="project-select" aria-label="${t('ui.topbar.activeProject', {}, 'Active project')}">
112
+ ${options}
113
+ </select>
114
+ </div>
115
+ `;
116
+ }
117
+
118
+ function _renderLocaleSelector(currentLocale) {
119
+ return `
120
+ <div class="project-select-wrapper locale-select-wrapper" title="${t('ui.topbar.language', {}, 'Language')}">
121
+ <select id="locale-select" aria-label="${t('ui.topbar.languageAria', {}, 'Select dashboard language')}">
122
+ <option value="es" ${currentLocale === 'es' ? 'selected' : ''}>${t('ui.topbar.languageEs', {}, 'ES')}</option>
123
+ <option value="en" ${currentLocale === 'en' ? 'selected' : ''}>${t('ui.topbar.languageEn', {}, 'EN')}</option>
124
+ </select>
125
+ </div>
126
+ `;
127
+ }
128
+
129
+ function _applyLocaleState(payload) {
130
+ if (!payload) return;
131
+ state.update('payload', payload);
132
+ if (payload.i18n) {
133
+ state.update({
134
+ phases: payload.i18n.phases || [],
135
+ statusLabels: payload.i18n.statusLabels || {},
136
+ locale: payload.i18n.locale || 'es',
137
+ messages: payload.i18n.messages || {},
138
+ });
139
+ }
140
+ }
141
+
142
+ function _bindEvents() {
143
+ // Hamburger → sidebar open
144
+ document.getElementById('sidebar-toggle')?.addEventListener('click', () => {
145
+ const sidebar = document.getElementById('sidebar');
146
+ const isOpen = sidebar?.classList.toggle('is-open');
147
+ document.getElementById('sidebar-toggle')?.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
148
+ });
149
+
150
+ // Theme toggle
151
+ theme.bindButton();
152
+
153
+ // Cerrar sidebar al hacer clic fuera (mobile)
154
+ document.addEventListener('click', e => {
155
+ const sidebar = document.getElementById('sidebar');
156
+ const toggle = document.getElementById('sidebar-toggle');
157
+ if (sidebar?.classList.contains('is-open') &&
158
+ !sidebar.contains(e.target) && !toggle?.contains(e.target)) {
159
+ sidebar.classList.remove('is-open');
160
+ toggle?.setAttribute('aria-expanded', 'false');
161
+ }
162
+ });
163
+
164
+ // Project selector
165
+ document.getElementById('project-select')?.addEventListener('change', async e => {
166
+ const id = e.target.value;
167
+ state.update('currentProjectId', id);
168
+ localStorage.setItem('ops-dashboard-project', id);
169
+ state.update('selectedTaskId', null);
170
+ // Trigger refresh global
171
+ window.dispatchEvent(new CustomEvent('ops:refresh'));
172
+ });
173
+
174
+ document.getElementById('locale-select')?.addEventListener('change', async e => {
175
+ const select = e.target;
176
+ const previousLocale = state.get('locale') || 'es';
177
+ const nextLocale = select.value;
178
+
179
+ if (nextLocale === previousLocale) return;
180
+
181
+ select.disabled = true;
182
+ try {
183
+ const result = await api.updateProjectLocale(nextLocale);
184
+ _applyLocaleState(result.state);
185
+ flash(t('ui.topbar.localeUpdated', {}, 'Language updated.'), 'success');
186
+ window.dispatchEvent(new CustomEvent('ops:refresh'));
187
+ } catch (err) {
188
+ select.value = previousLocale;
189
+ flash(err.message, 'error');
190
+ } finally {
191
+ select.disabled = false;
192
+ }
193
+ });
194
+
195
+ // Sync button
196
+ document.getElementById('sync-btn')?.addEventListener('click', async () => {
197
+ const btn = document.getElementById('sync-btn');
198
+ if (btn) { btn.disabled = true; btn.innerHTML = `${icon('sync', 16)} ${t('ui.topbar.syncing', {}, 'Syncing…')}`; }
199
+ try {
200
+ await api.syncDocs();
201
+ flash(t('ui.topbar.synced', {}, 'Documentation synced.'), 'success');
202
+ window.dispatchEvent(new CustomEvent('ops:refresh'));
203
+ } catch (err) {
204
+ flash(err.message, 'error');
205
+ } finally {
206
+ if (btn) { btn.disabled = false; btn.innerHTML = `${icon('sync', 16)} ${t('ui.topbar.sync', {}, 'Sync')}`; }
207
+ }
208
+ });
209
+
210
+ // Refresh button
211
+ document.getElementById('refresh-btn')?.addEventListener('click', () => {
212
+ window.dispatchEvent(new CustomEvent('ops:refresh'));
213
+ });
214
+
215
+ // Búsqueda global (debounced)
216
+ const searchInput = document.getElementById('global-search');
217
+ if (searchInput) {
218
+ const handleSearch = debounce(e => {
219
+ state.update('searchQuery', e.target.value);
220
+ window.dispatchEvent(new CustomEvent('ops:search', { detail: { query: e.target.value } }));
221
+ }, 250);
222
+ searchInput.addEventListener('input', handleSearch);
223
+
224
+ // Atajo de teclado ⌘/Ctrl+F
225
+ document.addEventListener('keydown', e => {
226
+ if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
227
+ e.preventDefault();
228
+ searchInput.focus();
229
+ searchInput.select();
230
+ }
231
+ });
232
+ }
233
+ }
234
+
235
+ /** Actualiza solo el timer del topbar sin re-renderizar */
236
+ export function updateTimer(display) {
237
+ const el = document.getElementById('topbar-timer-display');
238
+ if (el) el.textContent = display;
239
+ }
@@ -1,26 +0,0 @@
1
- # Agente del Proyecto: {{PROJECT_NAME}}
2
-
3
- ## Identidad
4
- Eres el agente principal del proyecto **{{PROJECT_NAME}}**. Este template existe por compatibilidad heredada y debe operar bajo el protocolo O.P.E.R.A. v3.0.
5
-
6
- ## Fuente de Verdad
7
- Tu fuente de verdad es `genesis.md`. Antes de tomar cualquier decisión, consulta este archivo.
8
- Para el seguimiento operativo y el estado del backlog, usa `project_control.json`.
9
-
10
- ## Comportamiento
11
- - Sigue las reglas de comportamiento definidas en `genesis.md`.
12
- - Respeta la Matriz de Autonomía (Semáforo) para determinar qué acciones puedes tomar.
13
- - Gestiona tareas y estados desde `project_control.json`.
14
- - No edites manualmente `task_plan.md`, `progress.md` ni `findings.md`; se regeneran con `trackops sync`.
15
-
16
- ## Skills Disponibles
17
- Consulta `.agents/skills/_registry.md` para ver las skills instaladas.
18
- También puedes buscar nuevas skills con `trackops skill catalog`.
19
-
20
- ## Ciclo de Trabajo
21
- 1. Ejecuta `trackops status` al inicio de cada bloque de trabajo.
22
- 2. Consulta `genesis.md` para entender los datos y reglas.
23
- 3. Usa `trackops next` para ver la siguiente cola priorizada.
24
- 4. Antes de implementar, marca la tarea con `trackops task start <task-id>`.
25
- 5. Usa el router (`.agent/hub/router.md`) para saber qué skill aplicar.
26
- 6. Al terminar, pasa la tarea a `review`, `complete` o `block` y ejecuta `trackops sync`.
@@ -1,94 +0,0 @@
1
- # {{PROJECT_NAME}} — Genesis
2
-
3
- > **La Constitución del proyecto.** Este documento es la fuente de verdad. Antes de tomar cualquier decisión arquitectónica o de implementación, consulta este archivo. Si un script contradice lo definido aquí, el script está mal.
4
-
5
- ---
6
-
7
- ## 1. Directriz Principal
8
-
9
- _¿Cuál es el resultado singular deseado de este proyecto?_
10
-
11
- > TODO: Definir el objetivo principal del proyecto.
12
-
13
- ---
14
-
15
- ## 2. Integraciones Externas
16
-
17
- _¿Qué servicios externos necesitamos? ¿Están listas las claves?_
18
-
19
- | Servicio | Estado | Clave / Config |
20
- |----------|--------|----------------|
21
- | — | — | — |
22
-
23
- ---
24
-
25
- ## 3. Fuente de la Verdad
26
-
27
- _¿Dónde viven los datos primarios?_
28
-
29
- > TODO: Describir la fuente de datos principal.
30
-
31
- ---
32
-
33
- ## 4. Carga Útil (Payload)
34
-
35
- _¿Cómo y dónde debe entregarse el resultado final?_
36
-
37
- > TODO: Describir destino y formato de entrega.
38
-
39
- ---
40
-
41
- ## 5. Reglas de Comportamiento
42
-
43
- _Restricciones, tono y reglas específicas del dominio._
44
-
45
- > TODO: Definir restricciones de negocio.
46
-
47
- ---
48
-
49
- ## Esquema de Datos
50
-
51
- > **Regla "Datos-Primero"**: Este schema debe estar definido antes de escribir cualquier código.
52
-
53
- ```json
54
- {
55
- "input": {
56
- "source": "",
57
- "schema": {}
58
- },
59
- "output": {
60
- "destination": "",
61
- "schema": {}
62
- }
63
- }
64
- ```
65
-
66
- ---
67
-
68
- ## Invariantes Arquitectónicas
69
-
70
- _Decisiones técnicas inamovibles. Cambiarlas requiere aprobación explícita (Nivel Rojo)._
71
-
72
- - TODO: Listar invariantes.
73
-
74
- ---
75
-
76
- ## Pipeline
77
-
78
- _Documenta el grafo de dependencias entre herramientas._
79
-
80
- <!-- Ejemplo:
81
- ### tool_fetch.py → tool_transform.py
82
- - Output: `.tmp/raw_data.json`
83
- - Formato: JSON array según schema X
84
- -->
85
-
86
- ---
87
-
88
- ## Templates
89
-
90
- _Referencias a las plantillas de output definidas en `templates/`._
91
-
92
- <!-- Ejemplo:
93
- - `templates/report.md` — Plantilla para reportes
94
- -->
@@ -1,117 +0,0 @@
1
- # Gobernanza, Autonomía y Recuperación
2
-
3
- Este documento define los niveles de permiso, el protocolo de auto-reparación y el sistema de rollback para el proyecto.
4
-
5
- ---
6
-
7
- ## 🚦 Matriz de Autonomía (Semáforo)
8
-
9
- ### 🔴 NIVEL ROJO — Detente y Pide Permiso
10
-
11
- Estas acciones requieren aprobación explícita del usuario antes de ejecutarse:
12
-
13
- - Modificar la estructura de datos o reglas en `genesis.md`.
14
- - Eliminar datos persistentes o archivos fuera de `.tmp/`.
15
- - Despliegue final a producción (Fase de Automatización).
16
- - Envío de comunicaciones reales a terceros (emails, webhooks con side-effects).
17
- - Creación de repositorios o recursos en servicios externos (GitHub, cloud).
18
- - Modificar configuraciones de acceso o seguridad.
19
-
20
- ### 🟡 NIVEL AMARILLO — Avanza con Precaución
21
-
22
- Estas acciones se pueden ejecutar pero requieren documentación inmediata:
23
-
24
- - Instalación de dependencias nuevas.
25
- - Modificaciones a la estructura de directorios.
26
- - Cambios en el pipeline documentado en `genesis.md`.
27
-
28
- ### 🟢 NIVEL VERDE — Avanza con Confianza
29
-
30
- Estas acciones no requieren permiso:
31
-
32
- - Creación, edición y corrección de scripts en `tools/`.
33
- - Lectura de archivos y documentación.
34
- - Ejecución de pruebas (Tests).
35
- - Actualización de `progress.md`, `findings.md` y `task_plan.md`.
36
- - Instalación de skills del ecosistema.
37
- - Escritura y limpieza de archivos en `.tmp/`.
38
- - Auto-Reparación (con límite de reintentos).
39
-
40
- ---
41
-
42
- ## 🛠️ Principio de Auto-Templado (Self-Annealing)
43
-
44
- Cuando una herramienta falla o ocurre un error en Nivel Verde, sigue este protocolo:
45
-
46
- ### Procedimiento
47
-
48
- 1. **Analizar**: Lee el stack trace completo. No adivines la causa.
49
- 2. **Parchear**: Arregla el script en `tools/`.
50
- 3. **Probar**: Verifica que el arreglo funciona ejecutando el script.
51
- 4. **Actualizar Memoria**: Documenta el aprendizaje en `findings.md` o en el SOP correspondiente en `architecture/` para que el error nunca se repita.
52
-
53
- ### Límite de Reintentos
54
-
55
- **Máximo 3 intentos de auto-reparación por error.** Si al tercer intento el error persiste:
56
-
57
- 1. **Escalar a Nivel Rojo** — Pide intervención humana.
58
- 2. **Documentar el bloqueo** en `findings.md` con:
59
-
60
- ```markdown
61
- ## Bloqueo: [nombre del error]
62
- ### Fecha: [YYYY-MM-DD]
63
- ### Script: [tools/nombre.py]
64
-
65
- ### Stack Trace
66
- [pegar stack trace completo]
67
-
68
- ### Intentos de Reparación
69
- 1. **Intento 1**: [qué se intentó] → [resultado]
70
- 2. **Intento 2**: [qué se intentó] → [resultado]
71
- 3. **Intento 3**: [qué se intentó] → [resultado]
72
-
73
- ### Hipótesis del Problema Raíz
74
- [análisis de por qué crees que falla]
75
-
76
- ### Acción Requerida
77
- [qué necesitas del usuario para desbloquear]
78
- ```
79
-
80
- ### Lo que NO es Auto-Templado
81
-
82
- - No es reintentar ciegamente el mismo comando esperando un resultado diferente.
83
- - No es ignorar el error y continuar.
84
- - No es cambiar el schema en `genesis.md` para que el error "desaparezca".
85
-
86
- ---
87
-
88
- ## 🔄 Protocolo de Rollback
89
-
90
- Si una fase posterior invalida una decisión de una fase anterior, NO modifiques `genesis.md` directamente.
91
-
92
- ### Procedimiento
93
-
94
- 1. **Documentar** en `CHANGELOG.md` qué cambio se necesita y por qué.
95
- 2. **Solicitar aprobación** (Nivel Rojo).
96
- 3. **Una vez aprobado**, actualizar `genesis.md` con nueva versión:
97
-
98
- ```markdown
99
- ## Versión 1.1 — [fecha]
100
-
101
- ### Cambio
102
- - [descripción precisa del cambio]
103
-
104
- ### Motivo
105
- - [por qué la versión anterior era incorrecta o insuficiente]
106
-
107
- ### Impacto
108
- - [qué scripts/SOPs necesitan actualizarse como consecuencia]
109
- ```
110
-
111
- 4. **Propagar el cambio**: Actualizar todos los scripts y SOPs afectados.
112
- 5. **Re-ejecutar tests**: Verificar que los cambios no rompen nada.
113
- 6. **Actualizar `progress.md`** con el rollback documentado.
114
-
115
- ### Regla de Oro
116
-
117
- El historial de decisiones nunca se borra. Cada versión de `genesis.md` queda registrada en `CHANGELOG.md`. Esto permite entender por qué se tomó una decisión y por qué se cambió, evitando ciclos de decisiones contradictorias.