trackops 2.0.5 → 2.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trackops",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Local control and coordination system for AI-agent software development",
5
5
  "main": "lib/control.js",
6
6
  "bin": {
@@ -26,13 +26,24 @@ function runNode(args, cwd, envOverrides = {}) {
26
26
  return result.stdout;
27
27
  }
28
28
 
29
- function runNodeResult(args, cwd, envOverrides = {}) {
30
- return spawnSync(process.execPath, args, {
31
- cwd,
32
- encoding: "utf8",
33
- env: { ...process.env, ...envOverrides },
34
- });
35
- }
29
+ function runNodeResult(args, cwd, envOverrides = {}) {
30
+ return spawnSync(process.execPath, args, {
31
+ cwd,
32
+ encoding: "utf8",
33
+ env: { ...process.env, ...envOverrides },
34
+ });
35
+ }
36
+
37
+ function runNodeWithInput(args, cwd, input, envOverrides = {}) {
38
+ const result = spawnSync(process.execPath, args, {
39
+ cwd,
40
+ encoding: "utf8",
41
+ input,
42
+ env: { ...process.env, ...envOverrides },
43
+ });
44
+ assert.strictEqual(result.status, 0, result.stderr || result.stdout || `fallo ejecutando ${args.join(" ")}`);
45
+ return result.stdout;
46
+ }
36
47
 
37
48
  function runCommand(command, args, cwd, envOverrides = {}) {
38
49
  return spawnSync(command, args, {
@@ -232,11 +243,12 @@ async function main() {
232
243
  const installedVersion = runNode([installedCli, "--version"], tempRoot);
233
244
  assert.strictEqual(installedVersion.trim(), packageVersion);
234
245
 
235
- const helpOutput = runNode([BIN, "help"], ROOT);
236
- assert.doesNotMatch(helpOutput, /\btrackops agent\b/i);
237
- assert.match(helpOutput, /workspace status\|migrate/i);
238
- assert.match(helpOutput, /env status\|sync/i);
239
- assert.match(helpOutput, /release \[--push\]/i);
246
+ const helpOutput = runNode([BIN, "help"], ROOT);
247
+ assert.doesNotMatch(helpOutput, /\btrackops agent\b/i);
248
+ assert.match(helpOutput, /workspace status\|migrate/i);
249
+ assert.match(helpOutput, /env status\|sync/i);
250
+ assert.match(helpOutput, /release \[--push\]/i);
251
+ assert.match(helpOutput, /--plain|--a11y/i);
240
252
 
241
253
  const versionOutput = runNode([BIN, "--version"], ROOT);
242
254
  assert.strictEqual(versionOutput.trim(), packageVersion);
@@ -270,31 +282,38 @@ async function main() {
270
282
  assert.match(projectLocaleDoctor, /Project language: es|Idioma del proyecto: es/);
271
283
  assert.match(projectLocaleDoctor, /Source: project|Origen: proyecto/);
272
284
 
273
- const statusFromWorkspace = runNode([BIN, "status"], splitProject);
274
- const statusFromApp = runNode([BIN, "status"], path.join(splitProject, "app"));
275
- const statusFromOps = runNode([BIN, "status"], path.join(splitProject, "ops"));
276
- assert.match(statusFromWorkspace, /Layout: split/);
277
- assert.match(statusFromApp, /Layout: split/);
278
- assert.match(statusFromOps, /Layout: split/);
279
-
280
- const nextOutput = runNode([BIN, "next"], splitProject);
281
- assert.match(nextOutput, /ops-bootstrap/);
282
-
283
- runNode([BIN, "sync"], splitProject);
285
+ const statusFromWorkspace = runNode([BIN, "status"], splitProject);
286
+ const statusFromApp = runNode([BIN, "status"], path.join(splitProject, "app"));
287
+ const statusFromOps = runNode([BIN, "status"], path.join(splitProject, "ops"));
288
+ assert.match(statusFromWorkspace, /Layout: split|Estructura: split/);
289
+ assert.match(statusFromApp, /Layout: split|Estructura: split/);
290
+ assert.match(statusFromOps, /Layout: split|Estructura: split/);
291
+ assert.match(statusFromWorkspace, /Git: not initialized|Git: no inicializado/i);
292
+ assert.doesNotMatch(statusFromWorkspace, /Branch: detached|Rama: detached/i);
293
+
294
+ const nextOutput = runNode([BIN, "next"], splitProject);
295
+ assert.match(nextOutput, /ops-bootstrap/);
296
+
297
+ const rerunInit = runNode([BIN, "init", "--locale", "es"], splitProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
298
+ assert.match(rerunInit, /Updated \.trackops-workspace\.json|Actualizado \.trackops-workspace\.json/);
299
+
300
+ runNode([BIN, "sync"], splitProject);
284
301
  for (const file of ["task_plan.md", "progress.md", "findings.md"]) {
285
302
  assert.ok(fs.existsSync(path.join(splitProject, "ops", file)), `${file} no fue generado en ops/`);
286
303
  }
287
-
288
- const envStatus = runNode([BIN, "env", "status"], splitProject);
289
- assert.match(envStatus, /Root \.env:/);
290
- assert.match(envStatus, /App bridge:/);
291
-
292
- const nonEmptyProject = path.join(tempRoot, "non-empty");
293
- fs.mkdirSync(nonEmptyProject, { recursive: true });
294
- writeJson(path.join(nonEmptyProject, "package.json"), { name: "existing-app", version: "1.0.0" });
295
- const initNonEmpty = runNodeResult([BIN, "init"], nonEmptyProject);
296
- assert.notStrictEqual(initNonEmpty.status, 0, "init debe abortar en directorios no vacios");
297
- assert.match(`${initNonEmpty.stdout}\n${initNonEmpty.stderr}`, /workspace migrate/i);
304
+
305
+ const envStatus = runNode([BIN, "env", "status"], splitProject);
306
+ assert.match(envStatus, /Root \.env:|\.env raiz:/);
307
+ assert.match(envStatus, /App bridge:|Puente app:/);
308
+
309
+ const nonEmptyProject = path.join(tempRoot, "non-empty");
310
+ fs.mkdirSync(nonEmptyProject, { recursive: true });
311
+ writeJson(path.join(nonEmptyProject, "package.json"), { name: "existing-app", version: "1.0.0" });
312
+ const initNonEmpty = runNode([BIN, "init", "--locale", "en"], nonEmptyProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
313
+ assert.match(initNonEmpty, /adopted into app\/|movio a app\//i);
314
+ assert.ok(fs.existsSync(path.join(nonEmptyProject, ".trackops-workspace.json")));
315
+ assert.ok(fs.existsSync(path.join(nonEmptyProject, "app", "package.json")));
316
+ assert.ok(fs.existsSync(path.join(nonEmptyProject, "ops", "project_control.json")));
298
317
 
299
318
  writeJson(path.join(splitProject, "app", "package.json"), {
300
319
  name: "split-demo",
@@ -361,9 +380,32 @@ async function main() {
361
380
  "--decision-ownership",
362
381
  "user",
363
382
  ], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
364
- const directControl = readJson(path.join(directProject, "ops", "project_control.json"));
365
- assert.strictEqual(directControl.meta.opera.bootstrap.mode, "direct_cli");
366
- assert.strictEqual(directControl.meta.opera.bootstrap.status, "awaiting_intake");
383
+ const directControl = readJson(path.join(directProject, "ops", "project_control.json"));
384
+ assert.strictEqual(directControl.meta.opera.bootstrap.mode, "direct_cli");
385
+ assert.strictEqual(directControl.meta.opera.bootstrap.status, "awaiting_intake");
386
+ assert.ok(fs.existsSync(path.join(directProject, "ops", "bootstrap", "intake.json")));
387
+ assert.ok(fs.existsSync(path.join(directProject, "ops", "bootstrap", "spec-dossier.md")));
388
+ assert.ok(fs.existsSync(path.join(directProject, "ops", "bootstrap", "open-questions.md")));
389
+ assert.ok(fs.existsSync(path.join(directProject, "ops", "bootstrap", "quality-report.json")));
390
+ const directOperaStatus = runNode([BIN, "opera", "status"], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
391
+ assert.match(directOperaStatus, /Intake:|Intake:/);
392
+ assert.match(directOperaStatus, /Spec dossier:|Specification brief:|Dossier de especificacion:/i);
393
+ assert.doesNotMatch(directOperaStatus, /The agent did not include|El agente no incluyo/i);
394
+ assert.doesNotMatch(directOperaStatus, /Handoff: ops[\\/]+bootstrap[\\/]+agent-handoff\.md/i);
395
+ const directHandoffSummary = runNode([BIN, "opera", "handoff"], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
396
+ assert.match(directHandoffSummary, /Guided bootstrap summary|Resumen del bootstrap guiado/i);
397
+ assert.doesNotMatch(directHandoffSummary, /Markdown handoff/i);
398
+
399
+ const plainStatus = runNode([BIN, "--plain", "status"], directProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
400
+ assert.match(plainStatus, /\[BLOCKED\]|\[PENDING\]/);
401
+ assert.doesNotMatch(plainStatus, /\u2500|\u23F3|\u26D4|\u2705/);
402
+
403
+ const promptProject = path.join(tempRoot, "prompt-demo");
404
+ fs.mkdirSync(promptProject, { recursive: true });
405
+ runNode([BIN, "init", "--locale", "en"], promptProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
406
+ writeJson(path.join(promptProject, "app", "package.json"), { name: "prompt-demo", version: "1.0.0" });
407
+ runNodeWithInput([BIN, "opera", "install", "--locale", "en"], promptProject, "\n", { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
408
+ assert.ok(!fs.existsSync(path.join(promptProject, "ops", "bootstrap", "agent-handoff.md")));
367
409
 
368
410
  writeJson(path.join(splitProject, "ops", "bootstrap", "intake.json"), {
369
411
  version: 1,
@@ -522,8 +564,8 @@ async function main() {
522
564
  version: "0.9.0",
523
565
  };
524
566
  writeJson(legacyUnsupportedControlPath, legacyUnsupportedControl);
525
- const legacyStatusOutput = runNode([BIN, "opera", "status"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
526
- assert.match(legacyStatusOutput, /legacy_unsupported/);
567
+ const legacyStatusOutput = runNode([BIN, "opera", "status"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
568
+ assert.match(legacyStatusOutput, /legacy_unsupported/);
527
569
  const upgradeWithoutReset = runNodeResult([BIN, "opera", "upgrade", "--stable"], legacyUnsupportedProject, { TRACKOPS_BOOTSTRAP_HOME: bootstrapHome });
528
570
  assert.strictEqual(upgradeWithoutReset.status, 0);
529
571
  assert.match(`${upgradeWithoutReset.stdout}\n${upgradeWithoutReset.stderr}`, /legacy/i);
@@ -2,8 +2,8 @@
2
2
  "name": "trackops",
3
3
  "shortDescription": "Global TrackOps skill that explains TrackOps, requires explicit runtime install, and guides per-repository activation.",
4
4
  "description": "Explains what TrackOps does, installs the global skill layer, requires explicit runtime installation with npm, supports Spanish and English, activates TrackOps repository by repository, and routes OPERA onboarding into either direct bootstrap or agent-led discovery.",
5
- "skillVersion": "2.0.5",
6
- "trackopsVersion": "2.0.5",
5
+ "skillVersion": "2.0.6",
6
+ "trackopsVersion": "2.0.6",
7
7
  "npmPackage": "trackops",
8
8
  "bootstrapPolicy": "explicit_install",
9
9
  "supportedAgentsV1": [