trackops 2.0.6 → 2.2.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 (60) hide show
  1. package/README.md +307 -701
  2. package/bin/trackops.js +24 -16
  3. package/lib/config.js +265 -58
  4. package/lib/control.js +830 -292
  5. package/lib/init.js +46 -16
  6. package/lib/opera-bootstrap.js +85 -45
  7. package/lib/opera-phase-dod.js +485 -0
  8. package/lib/opera.js +8 -5
  9. package/lib/plans.js +1329 -0
  10. package/lib/quality-assert.js +49 -0
  11. package/lib/quality.js +1759 -0
  12. package/lib/release.js +18 -11
  13. package/lib/server.js +504 -192
  14. package/lib/skills.js +94 -41
  15. package/locales/en.json +249 -15
  16. package/locales/es.json +249 -15
  17. package/package.json +3 -2
  18. package/scripts/quality-unit-tests.js +130 -0
  19. package/scripts/skills-marketplace-smoke.js +156 -124
  20. package/scripts/smoke-tests.js +378 -71
  21. package/scripts/sync-skill-version.js +29 -19
  22. package/scripts/validate-skill.js +188 -103
  23. package/skills/trackops/SKILL.md +25 -7
  24. package/skills/trackops/locales/en/SKILL.md +25 -7
  25. package/skills/trackops/locales/en/references/activation.md +3 -3
  26. package/skills/trackops/locales/en/references/workflow.md +5 -4
  27. package/skills/trackops/references/activation.md +3 -3
  28. package/skills/trackops/references/workflow.md +5 -4
  29. package/skills/trackops/skill.json +29 -29
  30. package/skills/trackops-quality-guard/SKILL.md +78 -0
  31. package/skills/trackops-quality-guard/agents/openai.yaml +7 -0
  32. package/skills/trackops-quality-guard/locales/en/SKILL.md +78 -0
  33. package/skills/trackops-quality-guard/locales/en/references/commands.md +36 -0
  34. package/skills/trackops-quality-guard/locales/en/references/decision-policy.md +16 -0
  35. package/skills/trackops-quality-guard/locales/en/references/output-format.md +24 -0
  36. package/skills/trackops-quality-guard/references/commands.md +36 -0
  37. package/skills/trackops-quality-guard/references/decision-policy.md +16 -0
  38. package/skills/trackops-quality-guard/references/output-format.md +24 -0
  39. package/skills/trackops-quality-guard/skill.json +28 -0
  40. package/templates/skills/opera-skill/SKILL.md +12 -0
  41. package/templates/skills/opera-skill/locales/en/SKILL.md +12 -0
  42. package/templates/skills/trackops-quality-guard/SKILL.md +72 -0
  43. package/templates/skills/trackops-quality-guard/locales/en/SKILL.md +72 -0
  44. package/templates/skills/trackops-quality-guard/locales/en/references/commands.md +30 -0
  45. package/templates/skills/trackops-quality-guard/locales/en/references/decision-policy.md +14 -0
  46. package/templates/skills/trackops-quality-guard/locales/en/references/output-format.md +21 -0
  47. package/templates/skills/trackops-quality-guard/references/commands.md +30 -0
  48. package/templates/skills/trackops-quality-guard/references/decision-policy.md +14 -0
  49. package/templates/skills/trackops-quality-guard/references/output-format.md +21 -0
  50. package/ui/js/api.js +93 -26
  51. package/ui/js/app.js +13 -7
  52. package/ui/js/filters.js +49 -29
  53. package/ui/js/time-tracker.js +41 -28
  54. package/ui/js/views/board.js +22 -14
  55. package/ui/js/views/dashboard.js +206 -49
  56. package/ui/js/views/execution.js +7 -3
  57. package/ui/js/views/plans.js +284 -0
  58. package/ui/js/views/scrum.js +25 -13
  59. package/ui/js/views/sidebar.js +9 -8
  60. package/ui/js/views/tasks.js +238 -134
package/lib/init.js CHANGED
@@ -102,7 +102,7 @@ function buildDefaultControl(context, options) {
102
102
  return {
103
103
  meta: {
104
104
  projectName: options.name || "My Project",
105
- controlVersion: 2,
105
+ controlVersion: config.DEFAULT_CONTROL_VERSION,
106
106
  locale,
107
107
  phases,
108
108
  updatedAt: nowIso(),
@@ -133,12 +133,31 @@ function buildDefaultControl(context, options) {
133
133
  explanationMode: null,
134
134
  capturedAt: null,
135
135
  },
136
- discovery: {
137
- projectState: null,
138
- documentationState: null,
139
- availableArtifacts: [],
140
- },
141
- },
136
+ discovery: {
137
+ projectState: null,
138
+ documentationState: null,
139
+ availableArtifacts: [],
140
+ },
141
+ quality: {
142
+ baselineProfile: "baseline",
143
+ activeProfiles: [],
144
+ verification: {
145
+ testCommands: [],
146
+ buildCommands: [],
147
+ smokeCommands: [],
148
+ reviewRequired: false,
149
+ },
150
+ lastReportAt: null,
151
+ lastVerificationAt: null,
152
+ lastReleaseReadiness: null,
153
+ lastPromotionReadiness: null,
154
+ },
155
+ agentInbox: {
156
+ pending: [],
157
+ history: [],
158
+ lastIssuedAt: null,
159
+ },
160
+ },
142
161
  checks: {
143
162
  lastBuild: { status: "pending", date: null, note: "" },
144
163
  lastTest: { status: "pending", date: null, note: "" },
@@ -153,19 +172,30 @@ function buildDefaultControl(context, options) {
153
172
  milestones: [],
154
173
  decisionsPending: [],
155
174
  tasks: [
156
- {
157
- id: "ops-bootstrap",
158
- title: t("init.defaultTaskTitle"),
175
+ {
176
+ id: "ops-bootstrap",
177
+ title: t("init.defaultTaskTitle"),
159
178
  phase: phases[0]?.id || "O",
160
179
  stream: "Operations",
161
180
  priority: "P0",
162
181
  status: "pending",
163
182
  required: true,
164
183
  dependsOn: [],
165
- summary: t("init.defaultTaskSummary"),
166
- acceptance: [],
167
- history: [{ at: nowIso(), action: "create", note: "trackops init" }],
168
- },
184
+ summary: t("init.defaultTaskSummary"),
185
+ acceptance: [],
186
+ execution: {
187
+ owner: config.DEFAULT_EXECUTION_OWNER,
188
+ lastActor: "system",
189
+ lastSource: "trackops_init",
190
+ currentSessionId: null,
191
+ lastSessionId: null,
192
+ lastSessionStatus: null,
193
+ awaitingUserConfirmation: false,
194
+ verificationPending: false,
195
+ updatedAt: nowIso(),
196
+ },
197
+ history: [{ at: nowIso(), action: "create", note: "trackops init" }],
198
+ },
169
199
  ],
170
200
  findings: [],
171
201
  };
@@ -300,7 +330,7 @@ function initSplitProject(root, options) {
300
330
  control = JSON.parse(fs.readFileSync(controlFile, "utf8"));
301
331
  if (!control.meta.phases) control.meta.phases = options.phases || config.buildDefaultPhases(options.locale);
302
332
  if (!control.meta.locale) control.meta.locale = options.locale || config.DEFAULT_LOCALE;
303
- if (!control.meta.controlVersion || control.meta.controlVersion < 2) control.meta.controlVersion = 2;
333
+ if (!control.meta.controlVersion || control.meta.controlVersion < config.DEFAULT_CONTROL_VERSION) control.meta.controlVersion = config.DEFAULT_CONTROL_VERSION;
304
334
  control.meta.updatedAt = nowIso();
305
335
  config.saveControl(context, control);
306
336
  } else {
@@ -358,7 +388,7 @@ function initLegacyProject(root, options) {
358
388
  const existing = JSON.parse(fs.readFileSync(controlFile, "utf8"));
359
389
  if (!existing.meta.phases) existing.meta.phases = options.phases || config.buildDefaultPhases(options.locale);
360
390
  if (!existing.meta.locale) existing.meta.locale = options.locale || config.DEFAULT_LOCALE;
361
- if (!existing.meta.controlVersion || existing.meta.controlVersion < 2) existing.meta.controlVersion = 2;
391
+ if (!existing.meta.controlVersion || existing.meta.controlVersion < config.DEFAULT_CONTROL_VERSION) existing.meta.controlVersion = config.DEFAULT_CONTROL_VERSION;
362
392
  existing.meta.updatedAt = nowIso();
363
393
  fs.writeFileSync(controlFile, `${JSON.stringify(existing, null, 2)}\n`, "utf8");
364
394
  console.log(t("init.updated", { file: "project_control.json" }));
@@ -442,16 +442,27 @@ function buildHandoffPrompt(control, profile) {
442
442
  t("handoff.instruction.intakeRequired"),
443
443
  "",
444
444
  "```json",
445
- JSON.stringify({
446
- problemStatement: "string — core problem the project solves",
447
- targetUser: "string — primary user persona",
448
- singularDesiredOutcome: "string — single most important outcome",
449
- sourceOfTruth: "string — authoritative data source",
450
- payload: "string — what gets delivered (NOT 'deliveryTarget')",
451
- decisionOwnership: "user | shared | agent",
452
- inputSchema: { "fieldName": "type — at least one key required" },
453
- outputSchema: { "fieldName": "type at least one key required" },
454
- }, null, 2),
445
+ JSON.stringify({
446
+ problemStatement: "string — core problem the project solves",
447
+ targetUser: "string — primary user persona",
448
+ singularDesiredOutcome: "string — single most important outcome",
449
+ sourceOfTruth: "string — authoritative data source",
450
+ payload: "string — what gets delivered (NOT 'deliveryTarget')",
451
+ decisionOwnership: "user | shared | agent",
452
+ versionControl: {
453
+ remote: "booleanwhether the project uses a remote VCS",
454
+ provider: "string — github | gitlab | bitbucket | other",
455
+ developmentBranch: "string — main development branch",
456
+ releaseBranch: "string — publish/release branch",
457
+ },
458
+ deployment: {
459
+ mode: "string — manual | ci | platform",
460
+ target: "string — staging | production | preview | custom",
461
+ smokeCommand: "string — command to validate a releasable/deployed build",
462
+ },
463
+ inputSchema: { "fieldName": "type — at least one key required" },
464
+ outputSchema: { "fieldName": "type — at least one key required" },
465
+ }, null, 2),
455
466
  "```",
456
467
  );
457
468
 
@@ -508,13 +519,24 @@ async function collectBootstrapProfile(root, control, options = {}) {
508
519
  sourceOfTruth: options.answers?.sourceOfTruth || previous.sourceOfTruth || scan.sourceOfTruthHint || "",
509
520
  payload: options.answers?.payload || previous.payload || scan.payloadHint || "",
510
521
  behaviorRules: normalizeList(options.answers?.behaviorRules || previous.behaviorRules || ""),
511
- inputSchema: options.answers?.inputSchema || previous.inputSchema || {},
512
- outputSchema: options.answers?.outputSchema || previous.outputSchema || {},
513
- architecturalInvariants: normalizeList(options.answers?.architecturalInvariants || previous.architecturalInvariants || ""),
514
- pipeline: normalizeList(options.answers?.pipeline || previous.pipeline || ""),
515
- templates: normalizeList(options.answers?.templates || previous.templates || ""),
516
- availableArtifacts: Array.isArray(previousDiscovery.availableArtifacts) ? previousDiscovery.availableArtifacts : [],
517
- };
522
+ inputSchema: options.answers?.inputSchema || previous.inputSchema || {},
523
+ outputSchema: options.answers?.outputSchema || previous.outputSchema || {},
524
+ architecturalInvariants: normalizeList(options.answers?.architecturalInvariants || previous.architecturalInvariants || ""),
525
+ pipeline: normalizeList(options.answers?.pipeline || previous.pipeline || ""),
526
+ templates: normalizeList(options.answers?.templates || previous.templates || ""),
527
+ versionControl: options.answers?.versionControl || previous.versionControl || {
528
+ remote: false,
529
+ provider: "",
530
+ developmentBranch: context.branches.development || "develop",
531
+ releaseBranch: context.branches.publish || "master",
532
+ },
533
+ deployment: options.answers?.deployment || previous.deployment || {
534
+ mode: "",
535
+ target: "",
536
+ smokeCommand: "",
537
+ },
538
+ availableArtifacts: Array.isArray(previousDiscovery.availableArtifacts) ? previousDiscovery.availableArtifacts : [],
539
+ };
518
540
 
519
541
  const answers = { ...defaults };
520
542
 
@@ -661,6 +683,17 @@ function buildDirectIntakeTemplate(profile) {
661
683
  architecturalInvariants: normalizeList(profile.discovery?.architecturalInvariants || []),
662
684
  pipeline: normalizeList(profile.discovery?.pipeline || []),
663
685
  templates: normalizeList(profile.discovery?.templates || []),
686
+ versionControl: profile.discovery?.versionControl || {
687
+ remote: false,
688
+ provider: "",
689
+ developmentBranch: "",
690
+ releaseBranch: "",
691
+ },
692
+ deployment: profile.discovery?.deployment || {
693
+ mode: "",
694
+ target: "",
695
+ smokeCommand: "",
696
+ },
664
697
  };
665
698
  }
666
699
 
@@ -715,6 +748,8 @@ function ensureDirectBootstrapArtifacts(context, profile) {
715
748
  inputSchema: intake.inputSchema || profile.discovery?.inputSchema || {},
716
749
  outputSchema: intake.outputSchema || profile.discovery?.outputSchema || {},
717
750
  decisionOwnership: intake.decisionOwnership || profile.discovery?.decisionOwnership || profile.decisionOwnership || null,
751
+ versionControl: intake.versionControl || profile.discovery?.versionControl || null,
752
+ deployment: intake.deployment || profile.discovery?.deployment || null,
718
753
  },
719
754
  };
720
755
  const qualityReport = buildQualityReport(context, mergedProfile, specText);
@@ -816,23 +851,25 @@ function buildOperatingContract(control, profile, qualityReport, context) {
816
851
  sourceArtifacts: discovery.availableArtifacts || [],
817
852
  repoScan: profile.inference || {},
818
853
  },
819
- system: {
820
- sourceOfTruth: discovery.sourceOfTruth || "",
821
- externalServices: discovery.externalServices || [],
822
- inputSchema: discovery.inputSchema || {},
823
- outputSchema: discovery.outputSchema || {},
824
- behaviorRules: discovery.behaviorRules || [],
825
- architecturalInvariants: discovery.architecturalInvariants || [],
826
- },
827
- execution: {
828
- pipeline: discovery.pipeline || [],
829
- templates: discovery.templates || [],
830
- phaseModel: "opera-v3",
831
- taskSeeds: buildSeedTasks(control, profile).map((task) => task.id),
832
- },
833
- governance: {
834
- policyFile: policyRelativePath(context),
835
- riskProfile: "standard",
854
+ system: {
855
+ sourceOfTruth: discovery.sourceOfTruth || "",
856
+ externalServices: discovery.externalServices || [],
857
+ inputSchema: discovery.inputSchema || {},
858
+ outputSchema: discovery.outputSchema || {},
859
+ behaviorRules: discovery.behaviorRules || [],
860
+ architecturalInvariants: discovery.architecturalInvariants || [],
861
+ },
862
+ execution: {
863
+ pipeline: discovery.pipeline || [],
864
+ templates: discovery.templates || [],
865
+ deployment: discovery.deployment || null,
866
+ phaseModel: "opera-v3",
867
+ taskSeeds: buildSeedTasks(control, profile).map((task) => task.id),
868
+ },
869
+ governance: {
870
+ policyFile: policyRelativePath(context),
871
+ versionControl: discovery.versionControl || null,
872
+ riskProfile: "standard",
836
873
  approvalRules: [
837
874
  "destructive_changes_require_approval",
838
875
  "production_deploy_requires_approval",
@@ -1216,11 +1253,13 @@ function resumeBootstrap(root, control) {
1216
1253
  externalServices: normalizeList(intake.externalServices || bootstrap.discovery?.externalServices || []),
1217
1254
  behaviorRules: normalizeList(intake.behaviorRules || bootstrap.discovery?.behaviorRules || []),
1218
1255
  architecturalInvariants: normalizeList(intake.architecturalInvariants || bootstrap.discovery?.architecturalInvariants || []),
1219
- pipeline: normalizeList(intake.pipeline || bootstrap.discovery?.pipeline || []),
1220
- templates: normalizeList(intake.templates || bootstrap.discovery?.templates || []),
1221
- inputSchema: intake.inputSchema || bootstrap.discovery?.inputSchema || {},
1222
- outputSchema: intake.outputSchema || bootstrap.discovery?.outputSchema || {},
1223
- };
1256
+ pipeline: normalizeList(intake.pipeline || bootstrap.discovery?.pipeline || []),
1257
+ templates: normalizeList(intake.templates || bootstrap.discovery?.templates || []),
1258
+ inputSchema: intake.inputSchema || bootstrap.discovery?.inputSchema || {},
1259
+ outputSchema: intake.outputSchema || bootstrap.discovery?.outputSchema || {},
1260
+ versionControl: intake.versionControl || bootstrap.discovery?.versionControl || null,
1261
+ deployment: intake.deployment || bootstrap.discovery?.deployment || null,
1262
+ };
1224
1263
  const missingFields = directMissingFields(discovery);
1225
1264
  const profile = {
1226
1265
  ...bootstrap,
@@ -1235,12 +1274,13 @@ function resumeBootstrap(root, control) {
1235
1274
  discovery,
1236
1275
  inference: scanProject(context),
1237
1276
  };
1238
- const qualityReport = buildQualityReport(context, profile, specDossier);
1239
- profile.status = qualityReport.status === "ready" ? "completed" : qualityReport.status;
1240
- profile.completedAt = qualityReport.status === "ready" ? nowIso() : null;
1241
- profile.qualityReport = qualityReport;
1242
- return { resumed: true, profile };
1243
- }
1277
+ const qualityReport = buildQualityReport(context, profile, specDossier);
1278
+ profile.status = qualityReport.status === "ready" ? "completed" : qualityReport.status;
1279
+ profile.completedAt = qualityReport.status === "ready" ? nowIso() : null;
1280
+ profile.missingFields = qualityReport.missingFields || [];
1281
+ profile.qualityReport = qualityReport;
1282
+ return { resumed: true, profile };
1283
+ }
1244
1284
 
1245
1285
  function detectLegacyBootstrap(root, control) {
1246
1286
  const context = config.ensureContext(root);