trackops 2.0.3 → 2.0.5

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 (103) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +695 -402
  3. package/bin/trackops.js +116 -116
  4. package/lib/config.js +326 -326
  5. package/lib/control.js +208 -208
  6. package/lib/env.js +244 -244
  7. package/lib/init.js +325 -325
  8. package/lib/locale.js +24 -0
  9. package/lib/opera-bootstrap.js +941 -874
  10. package/lib/opera.js +494 -477
  11. package/lib/preferences.js +74 -74
  12. package/lib/registry.js +214 -196
  13. package/lib/release.js +56 -56
  14. package/lib/runtime-state.js +144 -144
  15. package/lib/server.js +312 -207
  16. package/lib/skills.js +74 -57
  17. package/lib/workspace.js +260 -260
  18. package/locales/en.json +192 -166
  19. package/locales/es.json +192 -166
  20. package/package.json +61 -58
  21. package/scripts/postinstall-locale.js +21 -21
  22. package/scripts/skills-marketplace-smoke.js +124 -124
  23. package/scripts/smoke-tests.js +558 -554
  24. package/scripts/sync-skill-version.js +21 -21
  25. package/scripts/validate-skill.js +103 -103
  26. package/skills/trackops/SKILL.md +126 -122
  27. package/skills/trackops/agents/openai.yaml +7 -7
  28. package/skills/trackops/locales/en/SKILL.md +126 -122
  29. package/skills/trackops/locales/en/references/activation.md +94 -75
  30. package/skills/trackops/locales/en/references/troubleshooting.md +73 -55
  31. package/skills/trackops/locales/en/references/workflow.md +55 -32
  32. package/skills/trackops/references/activation.md +94 -75
  33. package/skills/trackops/references/troubleshooting.md +73 -55
  34. package/skills/trackops/references/workflow.md +55 -32
  35. package/skills/trackops/skill.json +29 -29
  36. package/templates/hooks/post-checkout +2 -2
  37. package/templates/hooks/post-commit +2 -2
  38. package/templates/hooks/post-merge +2 -2
  39. package/templates/opera/agent.md +28 -27
  40. package/templates/opera/architecture/dependency-graph.md +24 -24
  41. package/templates/opera/architecture/runtime-automation.md +24 -24
  42. package/templates/opera/architecture/runtime-operations.md +34 -34
  43. package/templates/opera/en/agent.md +22 -21
  44. package/templates/opera/en/architecture/dependency-graph.md +24 -24
  45. package/templates/opera/en/architecture/runtime-automation.md +24 -24
  46. package/templates/opera/en/architecture/runtime-operations.md +34 -34
  47. package/templates/opera/en/reviews/delivery-audit.md +18 -18
  48. package/templates/opera/en/reviews/integration-audit.md +18 -18
  49. package/templates/opera/en/router.md +24 -19
  50. package/templates/opera/references/autonomy-and-recovery.md +117 -117
  51. package/templates/opera/references/opera-cycle.md +193 -193
  52. package/templates/opera/registry.md +28 -28
  53. package/templates/opera/reviews/delivery-audit.md +18 -18
  54. package/templates/opera/reviews/integration-audit.md +18 -18
  55. package/templates/opera/router.md +54 -49
  56. package/templates/skills/changelog-updater/SKILL.md +69 -69
  57. package/templates/skills/commiter/SKILL.md +99 -99
  58. package/templates/skills/opera-contract-auditor/SKILL.md +38 -38
  59. package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -38
  60. package/templates/skills/opera-policy-guard/SKILL.md +26 -26
  61. package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -26
  62. package/templates/skills/opera-skill/SKILL.md +279 -0
  63. package/templates/skills/opera-skill/locales/en/SKILL.md +279 -0
  64. package/templates/skills/opera-skill/locales/en/references/phase-dod.md +138 -0
  65. package/templates/skills/opera-skill/references/phase-dod.md +138 -0
  66. package/templates/skills/project-starter-skill/SKILL.md +150 -131
  67. package/templates/skills/project-starter-skill/locales/en/SKILL.md +143 -105
  68. package/templates/skills/project-starter-skill/references/opera-cycle.md +195 -193
  69. package/ui/css/base.css +284 -266
  70. package/ui/css/charts.css +425 -327
  71. package/ui/css/components.css +1107 -570
  72. package/ui/css/onboarding.css +133 -0
  73. package/ui/css/panels.css +345 -406
  74. package/ui/css/terminal.css +125 -0
  75. package/ui/css/timeline.css +58 -0
  76. package/ui/css/tokens.css +284 -227
  77. package/ui/favicon.svg +5 -5
  78. package/ui/index.html +99 -96
  79. package/ui/js/api.js +49 -13
  80. package/ui/js/app.js +28 -32
  81. package/ui/js/charts.js +526 -0
  82. package/ui/js/console-logger.js +172 -172
  83. package/ui/js/filters.js +247 -0
  84. package/ui/js/icons.js +129 -104
  85. package/ui/js/keyboard.js +229 -0
  86. package/ui/js/onboarding.js +33 -42
  87. package/ui/js/router.js +142 -125
  88. package/ui/js/theme.js +100 -100
  89. package/ui/js/time-tracker.js +248 -248
  90. package/ui/js/views/board.js +84 -114
  91. package/ui/js/views/dashboard.js +870 -0
  92. package/ui/js/views/flash.js +47 -47
  93. package/ui/js/views/projects.js +745 -0
  94. package/ui/js/views/scrum.js +476 -0
  95. package/ui/js/views/settings.js +153 -203
  96. package/ui/js/views/sidebar.js +37 -31
  97. package/ui/js/views/tasks.js +218 -101
  98. package/ui/js/views/timeline.js +265 -0
  99. package/ui/js/views/topbar.js +94 -107
  100. package/ui/app.js +0 -950
  101. package/ui/js/views/insights.js +0 -340
  102. package/ui/js/views/overview.js +0 -369
  103. package/ui/styles.css +0 -688
package/ui/index.html CHANGED
@@ -1,96 +1,99 @@
1
- <!doctype html>
2
- <html lang="es">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>TrackOps Beta — Centro de control</title>
7
- <meta name="description" content="Panel local beta de TrackOps: gestión de proyectos, tareas, analíticas y seguimiento de tiempo para desarrolladores." />
8
- <link rel="icon" type="image/svg+xml" href="favicon.svg" />
9
-
10
- <!-- Google Fonts (coherente con web corporativa) -->
11
- <link rel="preconnect" href="https://fonts.googleapis.com" />
12
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
13
- <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@700;800&display=swap" rel="stylesheet" />
14
-
15
- <!-- Anti-FOUC: aplica el tema antes del primer paint -->
16
- <script>
17
- (function(){
18
- var t = localStorage.getItem('trackops-theme');
19
- if (!t) t = 'light';
20
- if (t === 'light') document.documentElement.setAttribute('data-theme','light');
21
- })();
22
- </script>
23
-
24
- <!-- CSS Modular -->
25
- <link rel="stylesheet" href="/css/tokens.css" />
26
- <link rel="stylesheet" href="/css/base.css" />
27
- <link rel="stylesheet" href="/css/components.css" />
28
- <link rel="stylesheet" href="/css/panels.css" />
29
- <link rel="stylesheet" href="/css/charts.css" />
30
- </head>
31
- <body>
32
-
33
- <!-- Skip to content (WCAG 2.2 AA) -->
34
- <a class="skip-link" href="#view-container">Saltar al contenido principal</a>
35
-
36
- <!-- App shell -->
37
- <div class="app-shell">
38
-
39
- <!-- ══ SIDEBAR ══ -->
40
- <aside id="sidebar" role="navigation" aria-label="Navegación principal">
41
- <!-- Rendered by sidebar.js -->
42
- </aside>
43
-
44
- <!-- ══ TOPBAR ══ -->
45
- <header id="topbar" role="banner">
46
- <!-- Rendered by topbar.js -->
47
- </header>
48
-
49
- <!-- ══ MAIN CONTENT ══ -->
50
- <main id="view-container" role="main" tabindex="-1">
51
- <!-- Rendered by router.js / views -->
52
- </main>
53
-
54
- </div><!-- /.app-shell -->
55
-
56
- <!-- Flash / Toast container (aria-live para a11y) -->
57
- <div id="flash-container" aria-live="polite" aria-atomic="false"></div>
58
-
59
- <!-- Panel de registros -->
60
- <div id="console-panel" class="console-panel" role="log" aria-label="Consola de errores" aria-live="off">
61
- <div class="console-panel-header">
62
- <div class="console-panel-title" id="console-panel-title">
63
- <span>·</span> Registros
64
- <span id="console-error-count" class="badge badge-danger" style="display:none">0</span>
65
- </div>
66
- <div class="console-panel-actions">
67
- <button class="btn btn-ghost btn-sm" id="console-clear-btn" type="button" aria-label="Limpiar logs">Limpiar</button>
68
- <button class="btn btn-ghost btn-sm" id="console-close-btn" type="button" aria-label="Cerrar consola">✕</button>
69
- </div>
70
- </div>
71
- <div class="console-logs" id="console-logs" role="list"></div>
72
- </div>
73
-
74
- <!-- Onboarding Spotlight -->
75
- <div id="onboarding-spotlight" class="onboarding-spotlight is-hidden" aria-hidden="true"></div>
76
-
77
- <div id="onboarding-tooltip" class="onboarding-tooltip is-hidden" role="dialog" aria-modal="true" aria-labelledby="ob-title">
78
- <div class="ob-step-label" id="ob-step-label">Paso 1 de X</div>
79
- <h2 class="ob-title" id="ob-title"></h2>
80
- <p class="ob-desc" id="ob-desc"></p>
81
-
82
- <div class="ob-nav">
83
- <div class="ob-dots" id="ob-dots" aria-hidden="true"></div>
84
- <div class="ob-actions">
85
- <button class="btn btn-ghost btn-sm" id="ob-skip" type="button">Saltar</button>
86
- <button class="btn btn-ghost btn-sm" id="ob-prev" type="button">Anterior</button>
87
- <button class="btn btn-primary btn-sm" id="ob-next" type="button">Siguiente</button>
88
- </div>
89
- </div>
90
- </div>
91
-
92
- <!-- JS Módulos (ES modules) -->
93
- <script type="module" src="/js/app.js"></script>
94
-
95
- </body>
96
- </html>
1
+ <!doctype html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>TrackOps Beta — Centro de control</title>
7
+ <meta name="description" content="Panel local beta de TrackOps: gestión de proyectos, tareas, analíticas y seguimiento de tiempo para desarrolladores." />
8
+ <link rel="icon" type="image/svg+xml" href="favicon.svg" />
9
+
10
+ <!-- Google Fonts (coherente con web corporativa) -->
11
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
12
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
13
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@700;800&display=swap" rel="stylesheet" />
14
+
15
+ <!-- Anti-FOUC: aplica el tema antes del primer paint -->
16
+ <script>
17
+ (function(){
18
+ var t = localStorage.getItem('trackops-theme');
19
+ if (!t) t = 'light';
20
+ if (t === 'light') document.documentElement.setAttribute('data-theme','light');
21
+ })();
22
+ </script>
23
+
24
+ <!-- CSS Modular -->
25
+ <link rel="stylesheet" href="/css/tokens.css" />
26
+ <link rel="stylesheet" href="/css/base.css" />
27
+ <link rel="stylesheet" href="/css/components.css" />
28
+ <link rel="stylesheet" href="/css/panels.css" />
29
+ <link rel="stylesheet" href="/css/charts.css" />
30
+ <link rel="stylesheet" href="/css/terminal.css" />
31
+ <link rel="stylesheet" href="/css/onboarding.css" />
32
+ <link rel="stylesheet" href="/css/timeline.css" />
33
+ </head>
34
+ <body>
35
+
36
+ <!-- Skip to content (WCAG 2.2 AA) -->
37
+ <a class="skip-link" href="#view-container">Saltar al contenido principal</a>
38
+
39
+ <!-- App shell -->
40
+ <div class="app-shell">
41
+
42
+ <!-- ══ SIDEBAR ══ -->
43
+ <aside id="sidebar" role="navigation" aria-label="Navegación principal">
44
+ <!-- Rendered by sidebar.js -->
45
+ </aside>
46
+
47
+ <!-- ══ TOPBAR ══ -->
48
+ <header id="topbar" role="banner">
49
+ <!-- Rendered by topbar.js -->
50
+ </header>
51
+
52
+ <!-- ══ MAIN CONTENT ══ -->
53
+ <main id="view-container" role="main" tabindex="-1">
54
+ <!-- Rendered by router.js / views -->
55
+ </main>
56
+
57
+ </div><!-- /.app-shell -->
58
+
59
+ <!-- Flash / Toast container (aria-live para a11y) -->
60
+ <div id="flash-container" aria-live="polite" aria-atomic="false"></div>
61
+
62
+ <!-- Panel de registros -->
63
+ <div id="console-panel" class="console-panel" role="log" aria-label="Consola de errores" aria-live="off">
64
+ <div class="console-panel-header">
65
+ <div class="console-panel-title" id="console-panel-title">
66
+ <span>·</span> Registros
67
+ <span id="console-error-count" class="badge badge-danger" style="display:none">0</span>
68
+ </div>
69
+ <div class="console-panel-actions">
70
+ <button class="btn btn-ghost btn-sm" id="console-clear-btn" type="button" aria-label="Limpiar logs">Limpiar</button>
71
+ <button class="btn btn-ghost btn-sm" id="console-close-btn" type="button" aria-label="Cerrar consola">✕</button>
72
+ </div>
73
+ </div>
74
+ <div class="console-logs" id="console-logs" role="list"></div>
75
+ </div>
76
+
77
+ <!-- Onboarding Spotlight -->
78
+ <div id="onboarding-spotlight" class="onboarding-spotlight is-hidden" aria-hidden="true"></div>
79
+
80
+ <div id="onboarding-tooltip" class="onboarding-tooltip is-hidden" role="dialog" aria-modal="true" aria-labelledby="ob-title">
81
+ <div class="ob-step-label" id="ob-step-label">Paso 1 de X</div>
82
+ <h2 class="ob-title" id="ob-title"></h2>
83
+ <p class="ob-desc" id="ob-desc"></p>
84
+
85
+ <div class="ob-nav">
86
+ <div class="ob-dots" id="ob-dots" aria-hidden="true"></div>
87
+ <div class="ob-actions">
88
+ <button class="btn btn-ghost btn-sm" id="ob-skip" type="button">Saltar</button>
89
+ <button class="btn btn-ghost btn-sm" id="ob-prev" type="button">Anterior</button>
90
+ <button class="btn btn-primary btn-sm" id="ob-next" type="button">Siguiente</button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- JS Módulos (ES modules) -->
96
+ <script type="module" src="/js/app.js"></script>
97
+
98
+ </body>
99
+ </html>
package/ui/js/api.js CHANGED
@@ -79,24 +79,50 @@ export async function updateProjectLocale(locale) {
79
79
  });
80
80
  }
81
81
 
82
+ /**
83
+ * Obtiene el estado de un proyecto especifico (sin cambiar el proyecto activo)
84
+ * @param {string} projectId
85
+ */
86
+ export async function getProjectState(projectId) {
87
+ return call(`/api/state?project=${encodeURIComponent(projectId)}`, { projectAware: false });
88
+ }
89
+
90
+ /**
91
+ * Elimina un proyecto del registro (no borra archivos)
92
+ * @param {string} projectId
93
+ */
94
+ export async function removeProject(projectId) {
95
+ return call(`/api/projects/${encodeURIComponent(projectId)}`, {
96
+ method: 'DELETE',
97
+ projectAware: false,
98
+ });
99
+ }
100
+
101
+ export async function purgeUnavailableProjects() {
102
+ return call('/api/projects/purge-unavailable', {
103
+ method: 'POST',
104
+ projectAware: false,
105
+ });
106
+ }
107
+
82
108
  // ─────────────────────────────── ESTADO ─────────────────────────────────────
83
109
 
84
110
  /**
85
111
  * Obtiene el estado completo del proyecto activo
86
112
  */
87
- export async function getState() {
88
- return call('/api/state');
89
- }
90
-
91
- export async function getEnvStatus() {
92
- return call('/api/env');
93
- }
94
-
95
- export async function syncEnv() {
96
- return call('/api/env/sync', {
97
- method: 'POST',
98
- });
99
- }
113
+ export async function getState() {
114
+ return call('/api/state');
115
+ }
116
+
117
+ export async function getEnvStatus() {
118
+ return call('/api/env');
119
+ }
120
+
121
+ export async function syncEnv() {
122
+ return call('/api/env/sync', {
123
+ method: 'POST',
124
+ });
125
+ }
100
126
 
101
127
  // ─────────────────────────────── TAREAS ─────────────────────────────────────
102
128
 
@@ -202,6 +228,16 @@ export async function getTimeEntries() {
202
228
  return call('/api/time');
203
229
  }
204
230
 
231
+ // ─────────────────────────────── ANALYTICS ────────────────────────────────
232
+
233
+ /**
234
+ * Obtiene datos analiticos computados del proyecto
235
+ * @param {string} [range='30'] — Rango en dias (7, 30, 90, 'all')
236
+ */
237
+ export async function getAnalytics(range = '30') {
238
+ return call(`/api/analytics?range=${encodeURIComponent(range)}`);
239
+ }
240
+
205
241
  // ─────────────────────────────── SKILLS HUB ────────────────────────────────
206
242
 
207
243
  export async function fetchSkillsLocal() {
package/ui/js/app.js CHANGED
@@ -10,17 +10,17 @@ import * as consoleLogger from './console-logger.js';
10
10
  import * as onboarding from './onboarding.js';
11
11
  import * as timeTracker from './time-tracker.js';
12
12
  import * as theme from './theme.js';
13
+ import * as keyboard from './keyboard.js';
13
14
 
14
15
  // Vistas
15
16
  import { render as renderSidebar } from './views/sidebar.js';
16
17
  import { render as renderTopbar } from './views/topbar.js';
17
- import { render as renderOverview } from './views/overview.js';
18
- import { render as renderBoard } from './views/board.js';
19
- import { render as renderTasks } from './views/tasks.js';
18
+ import * as dashboardView from './views/dashboard.js';
19
+ import * as tasksView from './views/tasks.js';
20
20
  import * as executionView from './views/execution.js';
21
- import { render as renderInsights } from './views/insights.js';
21
+ import * as projectsView from './views/projects.js';
22
+ import { render as renderTimeline } from './views/timeline.js';
22
23
  import * as settingsView from './views/settings.js';
23
- import * as skillsView from './views/skills.js';
24
24
 
25
25
  // ─────────────────────────────── INIT ───────────────────────────────────────
26
26
 
@@ -32,28 +32,32 @@ async function init() {
32
32
  consoleLogger.init();
33
33
 
34
34
  // 2. Registrar rutas en el router
35
- router.register('overview', renderOverview);
36
- router.register('board', renderBoard);
37
- router.register('tasks', renderTasks);
38
- router.register('execution', async () => {
35
+ router.register('dashboard', async () => {
36
+ const html = await dashboardView.render();
37
+ setTimeout(() => dashboardView.bindEvents?.(), 50);
38
+ return html;
39
+ });
40
+ router.register('tasks', async () => {
41
+ const html = await tasksView.render();
42
+ setTimeout(() => tasksView.bindEvents?.(), 50);
43
+ return html;
44
+ });
45
+ router.register('terminal', async () => {
39
46
  const html = await executionView.render();
40
47
  setTimeout(() => executionView.bindEvents(), 50);
41
48
  return html;
42
49
  });
43
- router.register('insights', renderInsights);
50
+ router.register('timeline', renderTimeline);
51
+ router.register('projects', async () => {
52
+ const html = await projectsView.render();
53
+ setTimeout(() => projectsView.bindEvents(), 50);
54
+ return html;
55
+ });
44
56
  router.register('settings', async () => {
45
57
  const html = await settingsView.render();
46
58
  setTimeout(() => settingsView.bindEvents(), 50);
47
59
  return html;
48
60
  });
49
- router.register('skills', async () => {
50
- const html = await skillsView.render();
51
- setTimeout(() => {
52
- skillsView.bindEvents();
53
- skillsView.loadData();
54
- }, 50);
55
- return html;
56
- });
57
61
 
58
62
  // 3. Inicializar el router
59
63
  router.init(document.getElementById('view-container'));
@@ -66,7 +70,7 @@ async function init() {
66
70
  renderTopbar();
67
71
 
68
72
  // 6. Navegar a la vista inicial
69
- await router.start('overview');
73
+ await router.start('dashboard');
70
74
 
71
75
  // 7. Cargar time entries en background
72
76
  timeTracker.loadEntries().catch(err => {
@@ -76,7 +80,10 @@ async function init() {
76
80
  // 8. Inicializar onboarding
77
81
  onboarding.init();
78
82
 
79
- // 9. Suscribir refreshes globales
83
+ // 9. Inicializar atajos de teclado
84
+ keyboard.init();
85
+
86
+ // 10. Suscribir refreshes globales
80
87
  _bindGlobalEvents();
81
88
 
82
89
  // 10. Auto-refresh cada 60s
@@ -161,22 +168,11 @@ function _bindGlobalEvents() {
161
168
  // Búsqueda global → refrescar la vista actual
162
169
  window.addEventListener('ops:search', () => {
163
170
  const active = router.current();
164
- if (active === 'board' || active === 'tasks') {
171
+ if (active === 'tasks') {
165
172
  router.refresh();
166
173
  }
167
174
  });
168
175
 
169
- // Navegación por teclado: Escape cierra modales / deselecciona
170
- document.addEventListener('keydown', e => {
171
- if (e.key === 'Escape') {
172
- // Deseleccionar tarea si no hay modal abierto
173
- const modalEl = document.querySelector('.modal-overlay:not(.is-hidden)');
174
- if (!modalEl) {
175
- // No deseleccionar: permite a las vistas manejar escape internamente
176
- }
177
- }
178
- });
179
-
180
176
  // Actualizar sidebar badges cuando cambia el payload
181
177
  state.subscribe('payload', () => {
182
178
  import('./views/sidebar.js').then(m => m.updateBadges?.());