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
package/ui/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>TrackOps Beta — Centro de control</title>
7
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" />
8
+ <link rel="icon" type="image/svg+xml" href="favicon.svg" />
9
9
 
10
10
  <!-- Google Fonts (coherente con web corporativa) -->
11
11
  <link rel="preconnect" href="https://fonts.googleapis.com" />
package/ui/js/api.js CHANGED
@@ -1,203 +1,220 @@
1
- /**
2
- * api.js — Capa de comunicación con el backend TrackOps
3
- * Wrapper sobre fetch con gestión de errores, project-awareness
4
- * y tipado de los endpoints disponibles en lib/server.js
5
- */
6
-
7
- import * as state from './state.js';
8
-
9
- /**
10
- * Llamada base a la API
11
- * @param {string} url
12
- * @param {RequestInit & { projectAware?: boolean }} options
13
- * @returns {Promise<Object>}
14
- */
15
- async function call(url, options = {}) {
16
- const target = new URL(url, window.location.origin);
17
- const currentId = state.get('currentProjectId');
18
- if (options.projectAware !== false && currentId && !target.searchParams.has('project')) {
19
- target.searchParams.set('project', currentId);
20
- }
21
-
22
- const response = await fetch(target, {
23
- ...options,
24
- headers: {
25
- 'Content-Type': 'application/json',
26
- ...(options.headers || {}),
27
- },
28
- });
29
-
30
- const text = await response.text();
31
- const json = text ? JSON.parse(text) : {};
32
-
33
- if (!response.ok || json.ok === false) {
34
- const err = new Error(json.error || `HTTP ${response.status}: ${response.statusText}`);
35
- err.status = response.status;
36
- throw err;
37
- }
38
-
39
- return json;
40
- }
41
-
42
- // ─────────────────────────────── PROYECTOS ──────────────────────────────────
43
-
44
- /**
45
- * Lista todos los proyectos del portfolio
46
- */
47
- export async function getProjects() {
48
- return call('/api/projects', { projectAware: false });
49
- }
50
-
51
- /**
52
- * Registra un proyecto existente en el portfolio
53
- * @param {string} root - ruta del directorio del proyecto
54
- */
55
- export async function registerProject(root) {
56
- return call('/api/projects/register', {
57
- method: 'POST',
58
- projectAware: false,
59
- body: JSON.stringify({ root }),
60
- });
61
- }
62
-
63
- /**
64
- * Instala trackops en un nuevo proyecto
65
- * @param {string} root
66
- */
67
- export async function installProject(root) {
68
- return call('/api/projects/install', {
69
- method: 'POST',
70
- projectAware: false,
71
- body: JSON.stringify({ root }),
72
- });
73
- }
74
-
75
- // ─────────────────────────────── ESTADO ─────────────────────────────────────
76
-
77
- /**
78
- * Obtiene el estado completo del proyecto activo
79
- */
1
+ /**
2
+ * api.js — Capa de comunicación con el backend TrackOps
3
+ * Wrapper sobre fetch con gestión de errores, project-awareness
4
+ * y tipado de los endpoints disponibles en lib/server.js
5
+ */
6
+
7
+ import * as state from './state.js';
8
+
9
+ /**
10
+ * Llamada base a la API
11
+ * @param {string} url
12
+ * @param {RequestInit & { projectAware?: boolean }} options
13
+ * @returns {Promise<Object>}
14
+ */
15
+ async function call(url, options = {}) {
16
+ const target = new URL(url, window.location.origin);
17
+ const currentId = state.get('currentProjectId');
18
+ if (options.projectAware !== false && currentId && !target.searchParams.has('project')) {
19
+ target.searchParams.set('project', currentId);
20
+ }
21
+
22
+ const response = await fetch(target, {
23
+ ...options,
24
+ headers: {
25
+ 'Content-Type': 'application/json',
26
+ ...(options.headers || {}),
27
+ },
28
+ });
29
+
30
+ const text = await response.text();
31
+ const json = text ? JSON.parse(text) : {};
32
+
33
+ if (!response.ok || json.ok === false) {
34
+ const err = new Error(json.error || `HTTP ${response.status}: ${response.statusText}`);
35
+ err.status = response.status;
36
+ throw err;
37
+ }
38
+
39
+ return json;
40
+ }
41
+
42
+ // ─────────────────────────────── PROYECTOS ──────────────────────────────────
43
+
44
+ /**
45
+ * Lista todos los proyectos del portfolio
46
+ */
47
+ export async function getProjects() {
48
+ return call('/api/projects', { projectAware: false });
49
+ }
50
+
51
+ /**
52
+ * Registra un proyecto existente en el portfolio
53
+ * @param {string} root - ruta del directorio del proyecto
54
+ */
55
+ export async function registerProject(root) {
56
+ return call('/api/projects/register', {
57
+ method: 'POST',
58
+ projectAware: false,
59
+ body: JSON.stringify({ root }),
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Instala trackops en un nuevo proyecto
65
+ * @param {string} root
66
+ */
67
+ export async function installProject(root, options = {}) {
68
+ return call('/api/projects/install', {
69
+ method: 'POST',
70
+ projectAware: false,
71
+ body: JSON.stringify({ root, ...options }),
72
+ });
73
+ }
74
+
75
+ export async function updateProjectLocale(locale) {
76
+ return call('/api/projects/locale', {
77
+ method: 'POST',
78
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), locale }),
79
+ });
80
+ }
81
+
82
+ // ─────────────────────────────── ESTADO ─────────────────────────────────────
83
+
84
+ /**
85
+ * Obtiene el estado completo del proyecto activo
86
+ */
80
87
  export async function getState() {
81
88
  return call('/api/state');
82
89
  }
83
90
 
84
- // ─────────────────────────────── TAREAS ─────────────────────────────────────
85
-
86
- /**
87
- * Crea una nueva tarea
88
- * @param {Object} payload
89
- */
90
- export async function createTask(payload) {
91
- return call('/api/tasks', {
92
- method: 'POST',
93
- body: JSON.stringify({ projectId: state.get('currentProjectId'), ...payload }),
94
- });
95
- }
96
-
97
- /**
98
- * Actualiza una tarea existente (edición completa)
99
- * @param {string} taskId
100
- * @param {Object} payload
101
- */
102
- export async function updateTask(taskId, payload) {
103
- return call(`/api/tasks/${encodeURIComponent(taskId)}`, {
104
- method: 'PUT',
105
- body: JSON.stringify({ projectId: state.get('currentProjectId'), ...payload }),
106
- });
107
- }
108
-
109
- /**
110
- * Ejecuta una acción sobre una tarea (start, review, complete, block, pending, cancel)
111
- * @param {string} taskId
112
- * @param {string} action
113
- * @param {string} [note]
114
- */
115
- export async function taskAction(taskId, action, note = '') {
116
- return call(`/api/tasks/${encodeURIComponent(taskId)}/action`, {
117
- method: 'POST',
118
- body: JSON.stringify({ projectId: state.get('currentProjectId'), action, note }),
119
- });
120
- }
121
-
122
- // ─────────────────────────────── SYNC ───────────────────────────────────────
123
-
124
- /**
125
- * Sincroniza los docs del proyecto (task_plan.md, progress.md, findings.md)
126
- */
127
- export async function syncDocs() {
128
- return call('/api/sync', {
129
- method: 'POST',
130
- body: JSON.stringify({ projectId: state.get('currentProjectId') }),
131
- });
132
- }
133
-
134
- // ─────────────────────────────── COMANDOS ───────────────────────────────────
135
-
136
- /**
137
- * Ejecuta un comando en el shell del proyecto
138
- * @param {string} command
139
- */
140
- export async function runCommand(command) {
141
- return call('/api/commands', {
142
- method: 'POST',
143
- body: JSON.stringify({ projectId: state.get('currentProjectId'), command }),
144
- });
145
- }
146
-
147
- /**
148
- * Crea un EventSource para hacer streaming de salida de una sesión
149
- * @param {string} sessionId
150
- * @returns {EventSource}
151
- */
152
- export function streamSession(sessionId) {
153
- return new EventSource(`/api/commands/${encodeURIComponent(sessionId)}/stream`);
154
- }
155
-
156
- // ─────────────────────────────── TIME TRACKING ──────────────────────────────
157
-
158
- /**
159
- * Inicia un time entry para una tarea
160
- * @param {string} taskId
161
- * @param {string} taskTitle
162
- */
163
- export async function startTimeEntry(taskId, taskTitle) {
164
- return call('/api/time/start', {
165
- method: 'POST',
166
- body: JSON.stringify({ projectId: state.get('currentProjectId'), taskId, taskTitle }),
167
- });
168
- }
169
-
170
- /**
171
- * Detiene el time entry activo
172
- * @param {string} entryId
173
- */
174
- export async function stopTimeEntry(entryId) {
175
- return call('/api/time/stop', {
176
- method: 'POST',
177
- body: JSON.stringify({ projectId: state.get('currentProjectId'), entryId }),
178
- });
179
- }
180
-
181
- /**
182
- * Obtiene los time entries del proyecto activo
183
- */
184
- export async function getTimeEntries() {
185
- return call('/api/time');
186
- }
187
-
188
- // ─────────────────────────────── SKILLS HUB ────────────────────────────────
189
-
190
- export async function fetchSkillsLocal() {
191
- return call('/api/skills/local');
192
- }
193
-
194
- export async function fetchSkillsDiscover() {
195
- return call('/api/skills/discover');
91
+ export async function getEnvStatus() {
92
+ return call('/api/env');
196
93
  }
197
94
 
198
- export async function installSkill(skillId) {
199
- return call('/api/skills/install', {
95
+ export async function syncEnv() {
96
+ return call('/api/env/sync', {
200
97
  method: 'POST',
201
- body: JSON.stringify({ skillId })
202
98
  });
203
99
  }
100
+
101
+ // ─────────────────────────────── TAREAS ─────────────────────────────────────
102
+
103
+ /**
104
+ * Crea una nueva tarea
105
+ * @param {Object} payload
106
+ */
107
+ export async function createTask(payload) {
108
+ return call('/api/tasks', {
109
+ method: 'POST',
110
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), ...payload }),
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Actualiza una tarea existente (edición completa)
116
+ * @param {string} taskId
117
+ * @param {Object} payload
118
+ */
119
+ export async function updateTask(taskId, payload) {
120
+ return call(`/api/tasks/${encodeURIComponent(taskId)}`, {
121
+ method: 'PUT',
122
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), ...payload }),
123
+ });
124
+ }
125
+
126
+ /**
127
+ * Ejecuta una acción sobre una tarea (start, review, complete, block, pending, cancel)
128
+ * @param {string} taskId
129
+ * @param {string} action
130
+ * @param {string} [note]
131
+ */
132
+ export async function taskAction(taskId, action, note = '') {
133
+ return call(`/api/tasks/${encodeURIComponent(taskId)}/action`, {
134
+ method: 'POST',
135
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), action, note }),
136
+ });
137
+ }
138
+
139
+ // ─────────────────────────────── SYNC ───────────────────────────────────────
140
+
141
+ /**
142
+ * Sincroniza los docs del proyecto (task_plan.md, progress.md, findings.md)
143
+ */
144
+ export async function syncDocs() {
145
+ return call('/api/sync', {
146
+ method: 'POST',
147
+ body: JSON.stringify({ projectId: state.get('currentProjectId') }),
148
+ });
149
+ }
150
+
151
+ // ─────────────────────────────── COMANDOS ───────────────────────────────────
152
+
153
+ /**
154
+ * Ejecuta un comando en el shell del proyecto
155
+ * @param {string} command
156
+ */
157
+ export async function runCommand(command) {
158
+ return call('/api/commands', {
159
+ method: 'POST',
160
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), command }),
161
+ });
162
+ }
163
+
164
+ /**
165
+ * Crea un EventSource para hacer streaming de salida de una sesión
166
+ * @param {string} sessionId
167
+ * @returns {EventSource}
168
+ */
169
+ export function streamSession(sessionId) {
170
+ return new EventSource(`/api/commands/${encodeURIComponent(sessionId)}/stream`);
171
+ }
172
+
173
+ // ─────────────────────────────── TIME TRACKING ──────────────────────────────
174
+
175
+ /**
176
+ * Inicia un time entry para una tarea
177
+ * @param {string} taskId
178
+ * @param {string} taskTitle
179
+ */
180
+ export async function startTimeEntry(taskId, taskTitle) {
181
+ return call('/api/time/start', {
182
+ method: 'POST',
183
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), taskId, taskTitle }),
184
+ });
185
+ }
186
+
187
+ /**
188
+ * Detiene el time entry activo
189
+ * @param {string} entryId
190
+ */
191
+ export async function stopTimeEntry(entryId) {
192
+ return call('/api/time/stop', {
193
+ method: 'POST',
194
+ body: JSON.stringify({ projectId: state.get('currentProjectId'), entryId }),
195
+ });
196
+ }
197
+
198
+ /**
199
+ * Obtiene los time entries del proyecto activo
200
+ */
201
+ export async function getTimeEntries() {
202
+ return call('/api/time');
203
+ }
204
+
205
+ // ─────────────────────────────── SKILLS HUB ────────────────────────────────
206
+
207
+ export async function fetchSkillsLocal() {
208
+ return call('/api/skills/local');
209
+ }
210
+
211
+ export async function fetchSkillsDiscover() {
212
+ return call('/api/skills/discover');
213
+ }
214
+
215
+ export async function installSkill(skillId) {
216
+ return call('/api/skills/install', {
217
+ method: 'POST',
218
+ body: JSON.stringify({ skillId })
219
+ });
220
+ }