trackops 1.1.0 → 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.
- 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 +57 -32
- package/skills/trackops/agents/openai.yaml +1 -1
- package/skills/trackops/references/activation.md +50 -16
- package/skills/trackops/references/troubleshooting.md +35 -20
- package/skills/trackops/references/workflow.md +18 -12
- 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.0",
|
|
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
|
@@ -2,63 +2,88 @@
|
|
|
2
2
|
name: "trackops"
|
|
3
3
|
description: "Global TrackOps skill that prepares your agent for local project orchestration and operational automation, ensures the runtime on first use, and guides per-project activation with optional OPERA."
|
|
4
4
|
metadata:
|
|
5
|
-
version: "
|
|
5
|
+
version: "2.0.0"
|
|
6
6
|
type: "global"
|
|
7
7
|
triggers:
|
|
8
8
|
- "install trackops"
|
|
9
9
|
- "skills.sh"
|
|
10
|
-
- "bootstrap trackops"
|
|
11
10
|
- "trackops init"
|
|
12
11
|
- "trackops opera install"
|
|
12
|
+
- "opera handoff"
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# TrackOps
|
|
16
16
|
|
|
17
|
-
Use this skill in two layers
|
|
17
|
+
Use this skill in two layers.
|
|
18
18
|
|
|
19
|
-
1. Global skill layer
|
|
20
|
-
Install it with:
|
|
19
|
+
## 1. Global skill layer
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
npx skills add Baxahaun/trackops --skill trackops --full-depth --global --agent codex -y
|
|
24
|
-
```
|
|
21
|
+
Install it with:
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npx skills add Baxahaun/trackops
|
|
25
|
+
```
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
Before relying on the CLI, run:
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
```bash
|
|
30
|
+
node scripts/bootstrap-trackops.js
|
|
31
|
+
```
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
Activate TrackOps inside the current repository with:
|
|
33
|
+
That bootstrap ensures the `trackops` runtime and records state in `~/.trackops/runtime.json`.
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
trackops init
|
|
39
|
-
```
|
|
35
|
+
## 2. Local project layer
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
Inside a repository:
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
```bash
|
|
40
|
+
trackops init
|
|
41
|
+
trackops opera install
|
|
42
|
+
```
|
|
46
43
|
|
|
47
44
|
Core rules:
|
|
48
45
|
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
46
|
+
- treat the global skill install as non-invasive
|
|
47
|
+
- use `ops/contract/operating-contract.json` as the machine contract when it exists
|
|
48
|
+
- use `ops/project_control.json` as the operational source of truth for backlog and state
|
|
49
|
+
- use `ops/policy/autonomy.json` before approval-sensitive actions
|
|
50
|
+
- use `/.env` and `/.env.example` as the environment contract
|
|
51
|
+
- keep generated operational docs under `ops/`
|
|
52
|
+
- support `trackops locale get|set` and `trackops doctor locale` when language matters
|
|
53
|
+
|
|
54
|
+
## OPERA onboarding
|
|
55
|
+
|
|
56
|
+
OPERA no longer assumes every user is technical.
|
|
57
|
+
|
|
58
|
+
When OPERA starts, TrackOps classifies:
|
|
59
|
+
|
|
60
|
+
- user technical level
|
|
61
|
+
- current project state
|
|
62
|
+
- available documentation
|
|
63
|
+
|
|
64
|
+
Then it chooses one of two routes:
|
|
65
|
+
|
|
66
|
+
- `direct bootstrap`
|
|
67
|
+
for technical users and already-defined repositories
|
|
68
|
+
- `agent handoff`
|
|
69
|
+
for early ideas, non-technical users, or weak documentation
|
|
70
|
+
|
|
71
|
+
If TrackOps routes bootstrap to the agent:
|
|
72
|
+
|
|
73
|
+
- read `ops/bootstrap/agent-handoff.md`
|
|
74
|
+
- or print it with `trackops opera handoff --print`
|
|
75
|
+
- the agent must produce:
|
|
76
|
+
- `ops/bootstrap/intake.json`
|
|
77
|
+
- `ops/bootstrap/spec-dossier.md`
|
|
78
|
+
- `ops/bootstrap/open-questions.md` when important gaps remain
|
|
79
|
+
- then resume with:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
trackops opera bootstrap --resume
|
|
83
|
+
```
|
|
56
84
|
|
|
57
85
|
Read references only when needed:
|
|
58
86
|
|
|
59
87
|
- `references/activation.md`
|
|
60
|
-
for install and activation flow
|
|
61
88
|
- `references/workflow.md`
|
|
62
|
-
for day-to-day repo operation
|
|
63
89
|
- `references/troubleshooting.md`
|
|
64
|
-
for bootstrap or environment issues
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "TrackOps"
|
|
3
|
-
short_description: "Global TrackOps skill for local project orchestration and operational automation"
|
|
3
|
+
short_description: "Global TrackOps skill for local project orchestration, bilingual onboarding, agent coordination, and operational automation"
|