trackops 1.1.0 → 2.0.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/README.md +194 -230
- package/bin/trackops.js +54 -28
- package/lib/config.js +14 -10
- package/lib/control.js +44 -32
- package/lib/env.js +18 -1
- package/lib/init.js +40 -6
- package/lib/opera-bootstrap.js +825 -273
- package/lib/opera.js +360 -110
- package/lib/preferences.js +74 -0
- package/lib/runtime-state.js +144 -0
- package/lib/server.js +155 -25
- package/locales/en.json +136 -42
- package/locales/es.json +136 -42
- package/package.json +2 -1
- package/scripts/postinstall-locale.js +21 -0
- package/scripts/smoke-tests.js +130 -5
- package/scripts/validate-skill.js +2 -1
- package/skills/trackops/SKILL.md +67 -45
- package/skills/trackops/agents/openai.yaml +5 -1
- package/skills/trackops/locales/en/SKILL.md +86 -0
- package/skills/trackops/locales/en/references/activation.md +73 -0
- package/skills/trackops/locales/en/references/troubleshooting.md +49 -0
- package/skills/trackops/locales/en/references/workflow.md +26 -0
- package/skills/trackops/references/activation.md +53 -19
- package/skills/trackops/references/troubleshooting.md +36 -21
- package/skills/trackops/references/workflow.md +21 -15
- package/skills/trackops/scripts/bootstrap-trackops.js +9 -7
- package/skills/trackops/skill.json +4 -4
- package/templates/opera/agent.md +10 -9
- package/templates/opera/architecture/dependency-graph.md +24 -0
- package/templates/opera/architecture/runtime-automation.md +24 -0
- package/templates/opera/architecture/runtime-operations.md +34 -0
- package/templates/opera/en/agent.md +21 -20
- package/templates/opera/en/architecture/dependency-graph.md +24 -0
- package/templates/opera/en/architecture/runtime-automation.md +24 -0
- package/templates/opera/en/architecture/runtime-operations.md +34 -0
- package/templates/opera/en/reviews/delivery-audit.md +18 -0
- package/templates/opera/en/reviews/integration-audit.md +18 -0
- package/templates/opera/en/router.md +19 -9
- package/templates/opera/reviews/delivery-audit.md +18 -0
- package/templates/opera/reviews/integration-audit.md +18 -0
- package/templates/opera/router.md +15 -5
- package/templates/skills/opera-contract-auditor/SKILL.md +38 -0
- package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -0
- package/templates/skills/opera-policy-guard/SKILL.md +26 -0
- package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -0
- package/templates/skills/project-starter-skill/SKILL.md +89 -164
- package/templates/skills/project-starter-skill/locales/en/SKILL.md +104 -24
- package/ui/js/views/overview.js +16 -12
- package/templates/etapa/agent.md +0 -26
- package/templates/etapa/genesis.md +0 -94
- package/templates/etapa/references/autonomy-and-recovery.md +0 -117
- package/templates/etapa/references/etapa-cycle.md +0 -193
- package/templates/etapa/registry.md +0 -28
- package/templates/etapa/router.md +0 -39
package/locales/es.json
CHANGED
|
@@ -101,8 +101,58 @@
|
|
|
101
101
|
"cli.next.stream": "stream",
|
|
102
102
|
"cli.next.summary": "resumen",
|
|
103
103
|
|
|
104
|
-
"cli.help.title": "Control operativo del proyecto",
|
|
105
|
-
"cli.help.usage": "Uso:",
|
|
104
|
+
"cli.help.title": "Control operativo del proyecto",
|
|
105
|
+
"cli.help.usage": "Uso:",
|
|
106
|
+
"cli.help.commands": "Comandos:",
|
|
107
|
+
"cli.help.init.desc": "Inicializa TrackOps en el directorio actual.",
|
|
108
|
+
"cli.help.workspace.desc": "Muestra o migra el layout actual del workspace.",
|
|
109
|
+
"cli.help.env.desc": "Audita o sincroniza el contrato .env del workspace.",
|
|
110
|
+
"cli.help.release.desc": "Publica el snapshot configurado de app/.",
|
|
111
|
+
"cli.help.version.desc": "Imprime la version instalada de TrackOps.",
|
|
112
|
+
"cli.help.status.desc": "Muestra el estado del proyecto: foco, fase activa, tareas listas, bloqueadores y repo.",
|
|
113
|
+
"cli.help.next.desc": "Cola priorizada de siguientes tareas ejecutables.",
|
|
114
|
+
"cli.help.sync.desc": "Regenera task_plan.md, progress.md y findings.md desde project_control.json.",
|
|
115
|
+
"cli.help.dashboard.desc": "Lanza el dashboard web local en un puerto libre e imprime URLs local/red.",
|
|
116
|
+
"cli.help.refreshRepo.desc": "Actualiza el snapshot runtime del repo con el estado git.",
|
|
117
|
+
"cli.help.installHooks.desc": "Configura git core.hooksPath para usar el directorio de hooks de TrackOps.",
|
|
118
|
+
"cli.help.register.desc": "Registra el proyecto actual en el portfolio multiproyecto.",
|
|
119
|
+
"cli.help.projects.desc": "Lista los proyectos registrados.",
|
|
120
|
+
"cli.help.task.desc": "Acciones: start, review, complete, block, pending, cancel, note.",
|
|
121
|
+
"cli.help.opera.desc": "Gestiona OPERA.",
|
|
122
|
+
"cli.help.opera.upgradeHint": "Upgrade: trackops opera upgrade --stable [--reset]",
|
|
123
|
+
"cli.help.locale.desc": "Muestra o actualiza el idioma global de TrackOps.",
|
|
124
|
+
"cli.help.doctor.desc": "Explica el origen efectivo del idioma para esta maquina/proyecto.",
|
|
125
|
+
"cli.help.skill.desc": "Gestiona skills.",
|
|
126
|
+
"cli.help.help.desc": "Muestra esta ayuda.",
|
|
127
|
+
"cli.help.globalWorkflow": "Flujo global del agente:",
|
|
128
|
+
"cli.help.globalWorkflow.line1": "Instala con 'npx skills add Baxahaun/trackops'",
|
|
129
|
+
"cli.help.globalWorkflow.line2": "y los flags globales/de agente que necesites; despues usa 'trackops init' y 'trackops opera install' de forma explicita dentro de cada proyecto.",
|
|
130
|
+
"cli.usage.workspace": "Uso: trackops workspace <status|migrate>",
|
|
131
|
+
"cli.usage.env": "Uso: trackops env <status|sync>",
|
|
132
|
+
"cli.usage.opera": "Uso: trackops opera <install|bootstrap|handoff|status|configure|upgrade>",
|
|
133
|
+
"cli.usage.skill": "Uso: trackops skill <install|list|remove|catalog> [name]",
|
|
134
|
+
"cli.usage.locale": "Uso: trackops locale <get|set> [es|en]",
|
|
135
|
+
"cli.usage.doctor": "Uso: trackops doctor locale",
|
|
136
|
+
"cli.error.unknownCommand": "Comando desconocido: {command}",
|
|
137
|
+
"cli.error.runHelp": "Ejecuta 'trackops help' para ver el uso.",
|
|
138
|
+
"cli.error.noWorkspace": "No se encontro ningun workspace TrackOps en este directorio ni en sus padres.",
|
|
139
|
+
"locale.effective": "Idioma efectivo",
|
|
140
|
+
"locale.source": "Origen",
|
|
141
|
+
"locale.global": "Idioma global",
|
|
142
|
+
"locale.project": "Idioma del proyecto",
|
|
143
|
+
"locale.env": "Idioma por entorno",
|
|
144
|
+
"locale.system": "Idioma del sistema",
|
|
145
|
+
"locale.runtimeFile": "Archivo runtime",
|
|
146
|
+
"locale.none": "ninguno",
|
|
147
|
+
"locale.invalid": "Idioma invalido: {value}.",
|
|
148
|
+
"locale.updated": "Idioma global actualizado a {locale}.",
|
|
149
|
+
"locale.source.explicit": "flag explicito",
|
|
150
|
+
"locale.source.project": "proyecto",
|
|
151
|
+
"locale.source.global": "global",
|
|
152
|
+
"locale.source.env": "entorno",
|
|
153
|
+
"locale.source.system": "sistema",
|
|
154
|
+
"locale.source.prompt": "prompt",
|
|
155
|
+
"locale.source.manual": "manual",
|
|
106
156
|
|
|
107
157
|
"server.ready": "Ops dashboard listo en http://{host}:{port}",
|
|
108
158
|
"server.bannerTitle": "Serving!",
|
|
@@ -138,11 +188,34 @@
|
|
|
138
188
|
"init.defaultTaskTitle": "Configurar proyecto con trackops",
|
|
139
189
|
"init.defaultTaskSummary": "Verificar estructura inicial, ajustar fases y confirmar integracion operativa.",
|
|
140
190
|
|
|
141
|
-
"opera.installed": "Metodologia OPERA instalada (v{version}).",
|
|
142
|
-
"opera.alreadyInstalled": "OPERA ya esta instalado en este proyecto (v{version}).",
|
|
143
|
-
"opera.notInstalled": "OPERA no esta instalado en este proyecto.",
|
|
144
|
-
"opera.upgraded": "OPERA actualizado a v{version}.",
|
|
145
|
-
"opera.primitiveDetected": "Detectada instalacion OPERA existente (sin gestion por Ops).",
|
|
191
|
+
"opera.installed": "Metodologia OPERA instalada (v{version}).",
|
|
192
|
+
"opera.alreadyInstalled": "OPERA ya esta instalado en este proyecto (v{version}).",
|
|
193
|
+
"opera.notInstalled": "OPERA no esta instalado en este proyecto.",
|
|
194
|
+
"opera.upgraded": "OPERA actualizado a v{version}.",
|
|
195
|
+
"opera.primitiveDetected": "Detectada instalacion OPERA existente (sin gestion por Ops).",
|
|
196
|
+
"opera.status.version": "OPERA v{version}",
|
|
197
|
+
"opera.status.installed": " Instalado: {value}",
|
|
198
|
+
"opera.status.skills": " Skills: {value}",
|
|
199
|
+
"opera.status.locale": " Idioma: {locale} ({source})",
|
|
200
|
+
"opera.status.legacy": " Legacy: {value}",
|
|
201
|
+
"opera.status.contractVersion": " Version de contrato: {value}",
|
|
202
|
+
"opera.status.contractReadiness": " Readiness del contrato: {value}",
|
|
203
|
+
"opera.status.bootstrap": " Bootstrap: {value}",
|
|
204
|
+
"opera.status.mode": " Modo: {value}",
|
|
205
|
+
"opera.status.route": " Ruta: {value}",
|
|
206
|
+
"opera.status.ownership": " Ownership: {value}",
|
|
207
|
+
"opera.status.missing": " Faltan: {value}",
|
|
208
|
+
"opera.status.resume": " Reanudar: trackops opera bootstrap --resume",
|
|
209
|
+
"opera.status.handoff": " Handoff: {value}",
|
|
210
|
+
"opera.status.qualityReport": " Quality report: {value}",
|
|
211
|
+
"opera.status.structure": " Estructura:",
|
|
212
|
+
"opera.configure.invalidPhases": "JSON de fases invalido.",
|
|
213
|
+
"opera.configure.updated": "Configuracion actualizada.",
|
|
214
|
+
"opera.upgrade.runInstallFirst": "Ejecuta 'trackops opera install' primero.",
|
|
215
|
+
"opera.upgrade.usage": "Uso: trackops opera upgrade --stable [--reset]",
|
|
216
|
+
"opera.upgrade.legacyUnsupported": "Proyecto OPERA legacy detectado. Ejecuta 'trackops opera upgrade --stable --reset' para moverlo al modelo estable actual.",
|
|
217
|
+
"opera.upgrade.backup": "Backup: {path}",
|
|
218
|
+
"postinstall.localeSet": "TrackOps ha fijado el idioma en '{locale}' ({source}).",
|
|
146
219
|
|
|
147
220
|
"skill.installed": "Skill '{name}' instalada.",
|
|
148
221
|
"skill.removed": "Skill '{name}' desinstalada.",
|
|
@@ -154,35 +227,47 @@
|
|
|
154
227
|
|
|
155
228
|
"cli.status.bootstrap": "Bootstrap: {status} | Idioma: {locale}",
|
|
156
229
|
|
|
157
|
-
"bootstrap.header": "Bootstrap OPERA",
|
|
158
|
-
"bootstrap.subtitle": "
|
|
159
|
-
"bootstrap.question.
|
|
160
|
-
"bootstrap.question.
|
|
161
|
-
"bootstrap.question.
|
|
162
|
-
"bootstrap.question.
|
|
163
|
-
"bootstrap.question.
|
|
230
|
+
"bootstrap.header": "Bootstrap OPERA",
|
|
231
|
+
"bootstrap.subtitle": "Primero clasifica al usuario y el estado del proyecto. TrackOps decidira si continuar por terminal o derivar el arranque al agente.",
|
|
232
|
+
"bootstrap.question.technicalLevel": "Nivel tecnico del usuario",
|
|
233
|
+
"bootstrap.question.projectState": "Estado actual del proyecto",
|
|
234
|
+
"bootstrap.question.docsState": "Documentacion disponible",
|
|
235
|
+
"bootstrap.question.decisionOwnership": "Quien debe tomar las decisiones clave",
|
|
236
|
+
"bootstrap.question.problemStatement": "Problema principal que se quiere resolver",
|
|
237
|
+
"bootstrap.question.targetUser": "Usuario objetivo principal",
|
|
238
|
+
"bootstrap.question.desiredOutcome": "Resultado singular deseado",
|
|
239
|
+
"bootstrap.question.externalServices": "Servicios externos (separados por comas)",
|
|
240
|
+
"bootstrap.question.sourceOfTruth": "Fuente de la verdad",
|
|
241
|
+
"bootstrap.question.payload": "Payload / objetivo de entrega",
|
|
242
|
+
"bootstrap.question.behaviorRules": "Reglas de comportamiento (separadas por punto y coma)",
|
|
164
243
|
"bootstrap.question.inputSchema": "Schema JSON de entrada",
|
|
165
244
|
"bootstrap.question.outputSchema": "Schema JSON de salida",
|
|
166
245
|
"bootstrap.question.invariants": "Invariantes arquitectonicas (separadas por punto y coma)",
|
|
167
246
|
"bootstrap.question.pipeline": "Pasos del pipeline (separados por punto y coma)",
|
|
168
|
-
"bootstrap.question.templates": "Archivos template (separados por comas)",
|
|
169
|
-
"bootstrap.question.repoTasks": "¿Incluir tareas opcionales de repo? [y/n]",
|
|
170
|
-
"bootstrap.completed": "Bootstrap OPERA completado.",
|
|
171
|
-
"bootstrap.pending": "Bootstrap OPERA guardado como pendiente. Reanuda con 'trackops opera bootstrap --resume'.",
|
|
172
|
-
"bootstrap.
|
|
173
|
-
"bootstrap.
|
|
174
|
-
"bootstrap.
|
|
175
|
-
"bootstrap.
|
|
176
|
-
"bootstrap.
|
|
177
|
-
"bootstrap.
|
|
178
|
-
"bootstrap.
|
|
179
|
-
"bootstrap.
|
|
180
|
-
"bootstrap.
|
|
181
|
-
"bootstrap.
|
|
182
|
-
"bootstrap.
|
|
183
|
-
"bootstrap.acceptance.
|
|
184
|
-
"bootstrap.acceptance.
|
|
185
|
-
"bootstrap.acceptance.
|
|
247
|
+
"bootstrap.question.templates": "Archivos template (separados por comas)",
|
|
248
|
+
"bootstrap.question.repoTasks": "¿Incluir tareas opcionales de repo? [y/n]",
|
|
249
|
+
"bootstrap.completed": "Bootstrap OPERA completado.",
|
|
250
|
+
"bootstrap.pending": "Bootstrap OPERA guardado como pendiente. Reanuda con 'trackops opera bootstrap --resume'.",
|
|
251
|
+
"bootstrap.awaitingAgent": "Bootstrap OPERA derivado al agente. Completa el handoff y reanuda con 'trackops opera bootstrap --resume'.",
|
|
252
|
+
"bootstrap.handoffFile": "Archivo de handoff",
|
|
253
|
+
"bootstrap.infer.envSourceHint": "Detectados archivos de entorno",
|
|
254
|
+
"bootstrap.noneDefined": "Aun no definido.",
|
|
255
|
+
"bootstrap.pendingValue": "Pendiente de definir.",
|
|
256
|
+
"bootstrap.servicePending": "pendiente",
|
|
257
|
+
"bootstrap.defaultFocus": "Completar bootstrap OPERA",
|
|
258
|
+
"bootstrap.defaultTarget": "Entrega objetivo pendiente de definir",
|
|
259
|
+
"bootstrap.blocker.missingData": "Todavia faltan datos clave del bootstrap.",
|
|
260
|
+
"bootstrap.blocker.awaitingAgent": "Esperando el resultado del handoff al agente.",
|
|
261
|
+
"bootstrap.history.seeded": "Sembrada por bootstrap OPERA.",
|
|
262
|
+
"bootstrap.acceptance.discovery": "Preguntas de descubrimiento respondidas.",
|
|
263
|
+
"bootstrap.acceptance.schema": "Schema de entrada/salida definido en genesis.md.",
|
|
264
|
+
"bootstrap.acceptance.rules": "Reglas de comportamiento documentadas.",
|
|
265
|
+
"bootstrap.acceptance.plan": "Plan revisado y aceptado.",
|
|
266
|
+
"bootstrap.acceptance.intake": "El agente genero ops/bootstrap/intake.json.",
|
|
267
|
+
"bootstrap.acceptance.specDossier": "El agente genero ops/bootstrap/spec-dossier.md.",
|
|
268
|
+
"bootstrap.acceptance.resume": "OPERA pudo ingerir el contexto y continuar.",
|
|
269
|
+
"bootstrap.acceptance.env": "Credenciales requeridas verificadas.",
|
|
270
|
+
"bootstrap.acceptance.tests": "Checks de conectividad pasando.",
|
|
186
271
|
"bootstrap.acceptance.shape": "Shapes externos validados contra genesis.md.",
|
|
187
272
|
"bootstrap.acceptance.findings": "Hallazgos documentados.",
|
|
188
273
|
"bootstrap.acceptance.sops": "SOPs documentados.",
|
|
@@ -196,9 +281,10 @@
|
|
|
196
281
|
"bootstrap.acceptance.deploy": "Despliegue completado.",
|
|
197
282
|
"bootstrap.acceptance.triggers": "Triggers configurados.",
|
|
198
283
|
"bootstrap.acceptance.smoke": "Smoke test pasando.",
|
|
199
|
-
"bootstrap.task.bootstrap.title": "Completar bootstrap OPERA",
|
|
200
|
-
"bootstrap.task.bootstrap.summary": "Convertir la estructura OPERA instalada en un modelo operativo especifico del proyecto.",
|
|
201
|
-
"bootstrap.task.
|
|
284
|
+
"bootstrap.task.bootstrap.title": "Completar bootstrap OPERA",
|
|
285
|
+
"bootstrap.task.bootstrap.summary": "Convertir la estructura OPERA instalada en un modelo operativo especifico del proyecto.",
|
|
286
|
+
"bootstrap.task.bootstrap.handoffSummary": "Preparar el handoff al agente para convertir una idea o especificacion parcial en contexto operativo estructurado.",
|
|
287
|
+
"bootstrap.task.prove.title": "Validar integraciones",
|
|
202
288
|
"bootstrap.task.prove.summary": "Verificar credenciales, conectividad y shape de respuestas antes de seguir construyendo.",
|
|
203
289
|
"bootstrap.task.structure.title": "Estructurar el sistema",
|
|
204
290
|
"bootstrap.task.structure.summary": "Documentar SOPs, implementar herramientas y capturar el grafo de dependencias.",
|
|
@@ -214,13 +300,21 @@
|
|
|
214
300
|
"bootstrap.task.repoChangelog.summary": "Decidir como se mantendra CHANGELOG.md en este proyecto.",
|
|
215
301
|
"bootstrap.task.repoGithub.title": "Revisar tareas de gobernanza GitHub",
|
|
216
302
|
"bootstrap.task.repoGithub.summary": "Comprobar si deben activarse tareas de automatizacion o gobernanza del repositorio.",
|
|
217
|
-
"bootstrap.field.
|
|
218
|
-
"bootstrap.field.
|
|
219
|
-
"bootstrap.field.
|
|
220
|
-
"bootstrap.field.
|
|
221
|
-
"bootstrap.field.
|
|
222
|
-
"bootstrap.
|
|
223
|
-
"bootstrap.
|
|
303
|
+
"bootstrap.field.singularDesiredOutcome": "Resultado deseado",
|
|
304
|
+
"bootstrap.field.desiredOutcome": "Resultado deseado",
|
|
305
|
+
"bootstrap.field.problemStatement": "Problema principal",
|
|
306
|
+
"bootstrap.field.targetUser": "Usuario objetivo",
|
|
307
|
+
"bootstrap.field.decisionOwnership": "Propiedad de decision",
|
|
308
|
+
"bootstrap.field.sourceOfTruth": "Fuente de la verdad",
|
|
309
|
+
"bootstrap.field.payload": "Payload",
|
|
310
|
+
"bootstrap.field.inputSchema": "Schema de entrada",
|
|
311
|
+
"bootstrap.field.outputSchema": "Schema de salida",
|
|
312
|
+
"bootstrap.field.intakeJson": "Archivo intake.json",
|
|
313
|
+
"bootstrap.field.specDossier": "Archivo spec-dossier.md",
|
|
314
|
+
"bootstrap.decisionImpact": "Necesario para completar el bootstrap OPERA.",
|
|
315
|
+
"bootstrap.pendingDecision.handoff": "Enviar el handoff de TrackOps al agente",
|
|
316
|
+
"bootstrap.pendingDecision.handoffImpact": "Necesario para que el agente genere intake.json y spec-dossier.md.",
|
|
317
|
+
"bootstrap.finding.genesisConflictTitle": "Genesis requiere revision manual",
|
|
224
318
|
"bootstrap.finding.genesisConflictDetail": "TrackOps detecto un genesis.md no plantilla y detuvo la sobreescritura automatica.",
|
|
225
319
|
"bootstrap.finding.genesisConflictImpact": "El bootstrap no puede completarse hasta revisar la constitucion existente.",
|
|
226
320
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trackops",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Operational project control with task management, document generation, multi-project dashboard, and optional OPERA methodology",
|
|
5
5
|
"main": "lib/control.js",
|
|
6
6
|
"bin": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"node": ">=18"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
|
+
"postinstall": "node scripts/postinstall-locale.js",
|
|
50
51
|
"test": "node scripts/smoke-tests.js",
|
|
51
52
|
"test:smoke": "node scripts/smoke-tests.js",
|
|
52
53
|
"skill:sync-version": "node scripts/sync-skill-version.js",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const runtimeState = require("../lib/runtime-state");
|
|
4
|
+
const { setLocale, t } = require("../lib/i18n");
|
|
5
|
+
|
|
6
|
+
function isGlobalInstall() {
|
|
7
|
+
return String(process.env.npm_config_global || "").toLowerCase() === "true";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
if (!isGlobalInstall()) return;
|
|
12
|
+
const result = await runtimeState.ensureGlobalLocale({ interactive: true });
|
|
13
|
+
if (!result?.locale) return;
|
|
14
|
+
setLocale(result.locale);
|
|
15
|
+
process.stdout.write(`${t("postinstall.localeSet", { locale: result.locale, source: t(`locale.source.${result.source}`) })}\n`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main().catch((error) => {
|
|
19
|
+
process.stderr.write(`${error.message}\n`);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
});
|
package/scripts/smoke-tests.js
CHANGED
|
@@ -231,6 +231,7 @@ async function main() {
|
|
|
231
231
|
assert.strictEqual(runtimeStamp.runtimeVersion, packageVersion);
|
|
232
232
|
assert.strictEqual(runtimeStamp.skill, "trackops");
|
|
233
233
|
assert.strictEqual(runtimeStamp.bootstrapPolicy, "first_use");
|
|
234
|
+
assert.ok(["es", "en"].includes(runtimeStamp.locale), "el bootstrap global debe fijar un idioma");
|
|
234
235
|
|
|
235
236
|
const installedCli = path.join(bootstrapPrefix, "node_modules", "trackops", "bin", "trackops.js");
|
|
236
237
|
assert.ok(fs.existsSync(installedCli), "el runtime instalado debe existir dentro del prefijo aislado");
|
|
@@ -256,9 +257,15 @@ async function main() {
|
|
|
256
257
|
const versionOutput = runNode([BIN, "--version"], ROOT);
|
|
257
258
|
assert.strictEqual(versionOutput.trim(), packageVersion);
|
|
258
259
|
|
|
260
|
+
runNode([BIN, "locale", "set", "en"], tempRoot, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
261
|
+
const localeGet = runNode([BIN, "locale", "get"], tempRoot, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
262
|
+
assert.match(localeGet, /Effective language: en|Idioma efectivo: en/);
|
|
263
|
+
const localeDoctor = runNode([BIN, "doctor", "locale"], tempRoot, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
264
|
+
assert.match(localeDoctor, /Source: global|Origen: global/);
|
|
265
|
+
|
|
259
266
|
const splitProject = path.join(tempRoot, "split-demo");
|
|
260
267
|
fs.mkdirSync(splitProject, { recursive: true });
|
|
261
|
-
runNode([BIN, "init"], splitProject);
|
|
268
|
+
runNode([BIN, "init", "--locale", "es"], splitProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
262
269
|
|
|
263
270
|
assert.ok(fs.existsSync(path.join(splitProject, ".trackops-workspace.json")));
|
|
264
271
|
assert.ok(fs.existsSync(path.join(splitProject, ".env")));
|
|
@@ -273,6 +280,11 @@ async function main() {
|
|
|
273
280
|
const splitControl = readJson(path.join(splitProject, "ops", "project_control.json"));
|
|
274
281
|
assert.strictEqual(splitControl.meta.workspace.layout, "split");
|
|
275
282
|
assert.strictEqual(splitControl.meta.environment.rootEnvFile, ".env");
|
|
283
|
+
assert.strictEqual(splitControl.meta.locale, "es");
|
|
284
|
+
|
|
285
|
+
const projectLocaleDoctor = runNode([BIN, "doctor", "locale"], splitProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
286
|
+
assert.match(projectLocaleDoctor, /Project language: es|Idioma del proyecto: es/);
|
|
287
|
+
assert.match(projectLocaleDoctor, /Source: project|Origen: proyecto/);
|
|
276
288
|
|
|
277
289
|
const statusFromWorkspace = runNode([BIN, "status"], splitProject);
|
|
278
290
|
const statusFromApp = runNode([BIN, "status"], path.join(splitProject, "app"));
|
|
@@ -311,27 +323,113 @@ async function main() {
|
|
|
311
323
|
assert.ok(fs.existsSync(path.join(splitProject, "ops", "genesis.md")));
|
|
312
324
|
assert.ok(fs.existsSync(path.join(splitProject, "ops", ".agent", "hub", "agent.md")));
|
|
313
325
|
assert.ok(fs.existsSync(path.join(splitProject, "ops", ".agents", "skills", "_registry.md")));
|
|
326
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "bootstrap", "agent-handoff.md")));
|
|
327
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "bootstrap", "agent-handoff.json")));
|
|
328
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "bootstrap", "open-questions.md")));
|
|
329
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "architecture", "runtime-operations.md")));
|
|
330
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "architecture", "dependency-graph.md")));
|
|
331
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "architecture", "runtime-automation.md")));
|
|
332
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "policy", "autonomy.json")));
|
|
333
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "reviews", "integration-audit.md")));
|
|
334
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "reviews", "delivery-audit.md")));
|
|
314
335
|
assert.ok(!fs.existsSync(path.join(splitProject, "genesis.md")));
|
|
315
336
|
|
|
316
337
|
const operaControl = readJson(path.join(splitProject, "ops", "project_control.json"));
|
|
317
338
|
assert.strictEqual(operaControl.meta.locale, "en");
|
|
318
339
|
assert.strictEqual(operaControl.meta.opera.installed, true);
|
|
340
|
+
assert.strictEqual(operaControl.meta.opera.bootstrap.mode, "agent_handoff");
|
|
341
|
+
assert.strictEqual(operaControl.meta.opera.bootstrap.status, "awaiting_agent");
|
|
342
|
+
assert.ok(operaControl.meta.opera.skills.includes("project-starter-skill"));
|
|
343
|
+
assert.ok(operaControl.meta.opera.skills.includes("opera-contract-auditor"));
|
|
344
|
+
assert.ok(operaControl.meta.opera.skills.includes("opera-policy-guard"));
|
|
319
345
|
assert.ok(operaControl.meta.environment.requiredKeys.includes("OPENAI_API_KEY"));
|
|
320
346
|
const envRootText = fs.readFileSync(path.join(splitProject, ".env"), "utf8");
|
|
321
347
|
assert.match(envRootText, /OPENAI_API_KEY=/);
|
|
322
348
|
|
|
323
|
-
const
|
|
349
|
+
const handoffPrint = runNode([BIN, "opera", "handoff", "--print"], splitProject);
|
|
350
|
+
assert.match(handoffPrint, /project-starter-skill/);
|
|
351
|
+
const handoffJson = JSON.parse(runNode([BIN, "opera", "handoff", "--json"], splitProject));
|
|
352
|
+
assert.strictEqual(handoffJson.skill, "project-starter-skill");
|
|
353
|
+
|
|
354
|
+
const directProject = path.join(tempRoot, "direct-demo");
|
|
355
|
+
fs.mkdirSync(directProject, { recursive: true });
|
|
356
|
+
runNode([BIN, "init", "--locale", "en"], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
357
|
+
writeJson(path.join(directProject, "app", "package.json"), { name: "direct-demo", version: "1.0.0" });
|
|
358
|
+
runNode([
|
|
359
|
+
BIN,
|
|
360
|
+
"opera",
|
|
361
|
+
"install",
|
|
362
|
+
"--locale",
|
|
363
|
+
"en",
|
|
364
|
+
"--non-interactive",
|
|
365
|
+
"--bootstrap-mode",
|
|
366
|
+
"direct",
|
|
367
|
+
"--technical-level",
|
|
368
|
+
"senior",
|
|
369
|
+
"--project-state",
|
|
370
|
+
"existing_repo",
|
|
371
|
+
"--docs-state",
|
|
372
|
+
"spec_dossier",
|
|
373
|
+
"--decision-ownership",
|
|
374
|
+
"user",
|
|
375
|
+
], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
376
|
+
const directControl = readJson(path.join(directProject, "ops", "project_control.json"));
|
|
377
|
+
assert.strictEqual(directControl.meta.opera.bootstrap.mode, "direct_cli");
|
|
378
|
+
assert.strictEqual(directControl.meta.opera.bootstrap.status, "awaiting_intake");
|
|
379
|
+
|
|
380
|
+
writeJson(path.join(splitProject, "ops", "bootstrap", "intake.json"), {
|
|
381
|
+
version: 1,
|
|
382
|
+
technicalLevel: "low",
|
|
383
|
+
projectState: "idea",
|
|
384
|
+
documentationState: "none",
|
|
385
|
+
decisionOwnership: "agent",
|
|
386
|
+
problemStatement: "users need a simple way to book and pay online",
|
|
387
|
+
targetUser: "small studio owners",
|
|
388
|
+
singularDesiredOutcome: "let users create and pay for bookings",
|
|
389
|
+
userLanguage: "en",
|
|
390
|
+
needsPlainLanguage: true,
|
|
391
|
+
recommendedStack: ["nextjs"],
|
|
392
|
+
externalServices: ["OpenAI", "Stripe"],
|
|
393
|
+
sourceOfTruth: "primary bookings database",
|
|
394
|
+
payload: "bookings dashboard",
|
|
395
|
+
behaviorRules: ["keep explanations simple"],
|
|
396
|
+
architecturalInvariants: ["keep app and ops separated"],
|
|
397
|
+
inputSchema: { booking: { email: "string" } },
|
|
398
|
+
outputSchema: { confirmation: { id: "string" } },
|
|
399
|
+
pipeline: ["create booking", "confirm payment"],
|
|
400
|
+
templates: ["booking-confirmation"],
|
|
401
|
+
});
|
|
402
|
+
fs.writeFileSync(
|
|
403
|
+
path.join(splitProject, "ops", "bootstrap", "spec-dossier.md"),
|
|
404
|
+
"# Spec dossier\n\n## Problem statement\nusers need a simple way to book and pay online\n\n## Target user\nsmall studio owners\n\n## Singular desired outcome\nlet users create and pay for bookings\n\n## Delivery target\nbookings dashboard\n\n## Source of truth\nprimary bookings database\n",
|
|
405
|
+
"utf8",
|
|
406
|
+
);
|
|
407
|
+
runNode([BIN, "opera", "bootstrap", "--resume"], splitProject);
|
|
408
|
+
const resumedControl = readJson(path.join(splitProject, "ops", "project_control.json"));
|
|
409
|
+
assert.strictEqual(resumedControl.meta.opera.bootstrap.status, "completed");
|
|
410
|
+
assert.strictEqual(resumedControl.meta.currentFocus, "let users create and pay for bookings");
|
|
411
|
+
assert.ok(resumedControl.meta.environment.requiredKeys.includes("STRIPE_SECRET_KEY"));
|
|
412
|
+
assert.ok(fs.existsSync(path.join(splitProject, "ops", "contract", "operating-contract.json")));
|
|
413
|
+
const operatingContract = readJson(path.join(splitProject, "ops", "contract", "operating-contract.json"));
|
|
414
|
+
assert.strictEqual(operatingContract.version, 3);
|
|
415
|
+
assert.strictEqual(operatingContract.userModel.language, "en");
|
|
416
|
+
assert.strictEqual(operatingContract.userModel.decisionOwnership, "agent");
|
|
417
|
+
|
|
324
418
|
const defaultDashboard = startDashboard(splitProject);
|
|
325
419
|
|
|
326
420
|
try {
|
|
327
421
|
const ready = await waitForDashboard(defaultDashboard);
|
|
328
422
|
const state = await get(ready.port, "/api/state");
|
|
329
423
|
const envPayload = await get(ready.port, "/api/env");
|
|
424
|
+
const operaBootstrapPayload = await get(ready.port, "/api/opera/bootstrap");
|
|
425
|
+
const operaHandoffPayload = await get(ready.port, "/api/opera/handoff");
|
|
330
426
|
const localSkills = await get(ready.port, "/api/skills/local");
|
|
331
427
|
const discoverSkills = await get(ready.port, "/api/skills/discover");
|
|
332
428
|
|
|
333
429
|
assert.strictEqual(state.status, 200);
|
|
334
430
|
assert.strictEqual(envPayload.status, 200);
|
|
431
|
+
assert.strictEqual(operaBootstrapPayload.status, 200);
|
|
432
|
+
assert.strictEqual(operaHandoffPayload.status, 200);
|
|
335
433
|
assert.strictEqual(localSkills.status, 200);
|
|
336
434
|
assert.strictEqual(discoverSkills.status, 200);
|
|
337
435
|
|
|
@@ -347,9 +445,14 @@ async function main() {
|
|
|
347
445
|
assert.ok(envState.requiredKeys.includes("OPENAI_API_KEY"));
|
|
348
446
|
assert.ok(envState.missingKeys.includes("OPENAI_API_KEY"));
|
|
349
447
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
448
|
+
const bootstrapState = JSON.parse(operaBootstrapPayload.body);
|
|
449
|
+
assert.strictEqual(bootstrapState.status, "completed");
|
|
450
|
+
assert.strictEqual(bootstrapState.contractVersion, 3);
|
|
451
|
+
assert.strictEqual(bootstrapState.contractReadiness, "verified");
|
|
452
|
+
const handoffState = JSON.parse(operaHandoffPayload.body);
|
|
453
|
+
assert.ok(handoffState.markdown.includes("project-starter-skill"));
|
|
454
|
+
assert.ok(handoffState.openQuestionsFile.endsWith("open-questions.md"));
|
|
455
|
+
|
|
353
456
|
} finally {
|
|
354
457
|
await stopDashboard(defaultDashboard);
|
|
355
458
|
}
|
|
@@ -420,6 +523,28 @@ async function main() {
|
|
|
420
523
|
assert.ok(!migratedPackage.scripts || !migratedPackage.scripts["ops:status"]);
|
|
421
524
|
assert.match(git(["branch", "--list"], legacyProject), /backup\/trackops-workspace-/);
|
|
422
525
|
|
|
526
|
+
const legacyUnsupportedProject = path.join(tempRoot, "legacy-unsupported");
|
|
527
|
+
fs.mkdirSync(legacyUnsupportedProject, { recursive: true });
|
|
528
|
+
initGitRepo(legacyUnsupportedProject);
|
|
529
|
+
runNode([BIN, "init", "--locale", "en"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
530
|
+
const legacyUnsupportedControlPath = path.join(legacyUnsupportedProject, "ops", "project_control.json");
|
|
531
|
+
const legacyUnsupportedControl = readJson(legacyUnsupportedControlPath);
|
|
532
|
+
legacyUnsupportedControl.meta.opera = {
|
|
533
|
+
installed: true,
|
|
534
|
+
version: "0.9.0",
|
|
535
|
+
};
|
|
536
|
+
writeJson(legacyUnsupportedControlPath, legacyUnsupportedControl);
|
|
537
|
+
const legacyStatusOutput = runNode([BIN, "opera", "status"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
538
|
+
assert.match(legacyStatusOutput, /legacy_unsupported/);
|
|
539
|
+
const upgradeWithoutReset = runNodeResult([BIN, "opera", "upgrade", "--stable"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
540
|
+
assert.strictEqual(upgradeWithoutReset.status, 0);
|
|
541
|
+
assert.match(`${upgradeWithoutReset.stdout}\n${upgradeWithoutReset.stderr}`, /legacy/i);
|
|
542
|
+
runNode([BIN, "opera", "upgrade", "--stable", "--reset"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
|
|
543
|
+
const upgradedLegacyControl = readJson(legacyUnsupportedControlPath);
|
|
544
|
+
assert.strictEqual(upgradedLegacyControl.meta.opera.legacyStatus, "supported");
|
|
545
|
+
assert.strictEqual(upgradedLegacyControl.meta.opera.stableTag, "stable");
|
|
546
|
+
assert.ok(fs.existsSync(path.join(legacyUnsupportedProject, "ops", ".tmp", "upgrade-backups")));
|
|
547
|
+
|
|
423
548
|
const releaseProject = path.join(tempRoot, "release-demo");
|
|
424
549
|
fs.mkdirSync(releaseProject, { recursive: true });
|
|
425
550
|
initGitRepo(releaseProject);
|
|
@@ -72,10 +72,11 @@ function main() {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
for (const requiredPhrase of [
|
|
75
|
-
"npx skills add Baxahaun/trackops
|
|
75
|
+
"npx skills add Baxahaun/trackops",
|
|
76
76
|
"node scripts/bootstrap-trackops.js",
|
|
77
77
|
"trackops init",
|
|
78
78
|
"trackops opera install",
|
|
79
|
+
"trackops opera bootstrap --resume",
|
|
79
80
|
]) {
|
|
80
81
|
if (!skillMd.includes(requiredPhrase)) {
|
|
81
82
|
fail(`skills/trackops/SKILL.md must mention '${requiredPhrase}'.`);
|
package/skills/trackops/SKILL.md
CHANGED
|
@@ -1,64 +1,86 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "trackops"
|
|
3
|
-
description: "
|
|
4
|
-
metadata:
|
|
5
|
-
version: "1.1.0"
|
|
6
|
-
type: "global"
|
|
7
|
-
triggers:
|
|
8
|
-
- "install trackops"
|
|
9
|
-
- "skills.sh"
|
|
10
|
-
- "bootstrap trackops"
|
|
11
|
-
- "trackops init"
|
|
12
|
-
- "trackops opera install"
|
|
3
|
+
description: "Skill global de TrackOps para instalar y activar la orquestacion local de proyectos con OPERA, entorno y handoff a agentes. Usala cuando el usuario quiera instalar TrackOps desde skills.sh, bootstrapear el runtime con `node scripts/bootstrap-trackops.js`, ejecutar `trackops init`, ejecutar `trackops opera install`, revisar `trackops opera handoff`, o trabajar sobre el flujo operativo de un repositorio."
|
|
13
4
|
---
|
|
14
5
|
|
|
15
6
|
# TrackOps
|
|
16
7
|
|
|
17
|
-
|
|
8
|
+
Si la conversacion y el proyecto deben trabajar en ingles, lee `locales/en/SKILL.md` antes de seguir.
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
Install it with:
|
|
10
|
+
## Capa global
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
npx skills add Baxahaun/trackops --skill trackops --full-depth --global --agent codex -y
|
|
24
|
-
```
|
|
12
|
+
Instala la skill del marketplace con:
|
|
25
13
|
|
|
26
|
-
|
|
14
|
+
```bash
|
|
15
|
+
npx skills add Baxahaun/trackops
|
|
16
|
+
```
|
|
27
17
|
|
|
28
|
-
|
|
18
|
+
Antes de depender del CLI, ejecuta el script empaquetado de la skill:
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
```bash
|
|
21
|
+
node scripts/bootstrap-trackops.js
|
|
22
|
+
```
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
Activate TrackOps inside the current repository with:
|
|
24
|
+
Ese bootstrap:
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
- asegura el runtime npm de `trackops`
|
|
27
|
+
- valida que el binario global sea ejecutable
|
|
28
|
+
- registra estado en `~/.trackops/runtime.json`
|
|
40
29
|
|
|
41
|
-
|
|
30
|
+
No debe crear archivos dentro de un repositorio por si solo.
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
trackops opera install
|
|
45
|
-
```
|
|
32
|
+
## Capa local del proyecto
|
|
46
33
|
|
|
47
|
-
|
|
34
|
+
Dentro del repositorio:
|
|
48
35
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- Treat `trackops init --with-opera` as a shortcut, not as the primary mental model.
|
|
54
|
-
- TrackOps manages `/.env` and `/.env.example` at workspace root. Do not print or persist secret values.
|
|
55
|
-
- Remember that skills installs from committed Git state.
|
|
36
|
+
```bash
|
|
37
|
+
trackops init
|
|
38
|
+
trackops opera install
|
|
39
|
+
```
|
|
56
40
|
|
|
57
|
-
|
|
41
|
+
Reglas base:
|
|
58
42
|
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
- `
|
|
62
|
-
|
|
63
|
-
- `
|
|
64
|
-
|
|
43
|
+
- trata la instalacion global como no invasiva
|
|
44
|
+
- usa `ops/contract/operating-contract.json` como contrato de maquina cuando exista
|
|
45
|
+
- usa `ops/project_control.json` como fuente de verdad operativa
|
|
46
|
+
- usa `ops/policy/autonomy.json` antes de acciones sensibles
|
|
47
|
+
- usa `/.env` y `/.env.example` como contrato de entorno
|
|
48
|
+
- deja la documentacion operativa generada dentro de `ops/`
|
|
49
|
+
- usa `trackops locale get|set` y `trackops doctor locale` cuando el idioma importe
|
|
50
|
+
|
|
51
|
+
## Onboarding de OPERA
|
|
52
|
+
|
|
53
|
+
OPERA ya no asume que todo usuario es tecnico.
|
|
54
|
+
|
|
55
|
+
TrackOps clasifica:
|
|
56
|
+
|
|
57
|
+
- nivel tecnico del usuario
|
|
58
|
+
- estado actual del proyecto
|
|
59
|
+
- documentacion disponible
|
|
60
|
+
|
|
61
|
+
Luego elige una de dos rutas:
|
|
62
|
+
|
|
63
|
+
- `direct bootstrap`
|
|
64
|
+
para usuarios tecnicos y repos ya definidos
|
|
65
|
+
- `agent handoff`
|
|
66
|
+
para ideas tempranas, usuarios no tecnicos o documentacion debil
|
|
67
|
+
|
|
68
|
+
Si TrackOps deriva al agente:
|
|
69
|
+
|
|
70
|
+
- lee `ops/bootstrap/agent-handoff.md`
|
|
71
|
+
- o imprimelo con `trackops opera handoff --print`
|
|
72
|
+
- exige como salida:
|
|
73
|
+
- `ops/bootstrap/intake.json`
|
|
74
|
+
- `ops/bootstrap/spec-dossier.md`
|
|
75
|
+
- `ops/bootstrap/open-questions.md` cuando queden huecos importantes
|
|
76
|
+
- reanuda con:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
trackops opera bootstrap --resume
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Que referencia leer y cuando
|
|
83
|
+
|
|
84
|
+
- lee `references/activation.md` solo para instalacion, primer uso, locale bootstrap y activacion de un repo
|
|
85
|
+
- lee `references/workflow.md` solo cuando TrackOps ya esta activo y haga falta operar el dia a dia del repositorio
|
|
86
|
+
- lee `references/troubleshooting.md` solo cuando fallen la instalacion, el bootstrap, el resume o el contrato de entorno
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "TrackOps"
|
|
3
|
-
short_description: "
|
|
3
|
+
short_description: "Bootstrap TrackOps and activate OPERA"
|
|
4
|
+
default_prompt: "Use $trackops to bootstrap the TrackOps runtime and activate OPERA in this repository."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|