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
@@ -1,124 +1,156 @@
1
- #!/usr/bin/env node
2
-
3
- const assert = require("assert");
4
- const fs = require("fs");
5
- const os = require("os");
6
- const path = require("path");
7
- const { spawnSync } = require("child_process");
8
-
9
- const ROOT = path.resolve(__dirname, "..");
10
- const SKILL_DIR = path.join(ROOT, "skills", "trackops");
11
- const SKILL_CONFIG = JSON.parse(fs.readFileSync(path.join(SKILL_DIR, "skill.json"), "utf8"));
12
-
13
- function run(command, args, cwd, envOverrides = {}) {
14
- const shell = process.platform === "win32" && /\.(cmd|bat)$/i.test(command);
15
- return spawnSync(command, args, {
16
- cwd,
17
- encoding: "utf8",
18
- env: { ...process.env, ...envOverrides },
19
- shell,
20
- });
21
- }
22
-
23
- function getNpxCommand() {
24
- return process.platform === "win32" ? "npx.cmd" : "npx";
25
- }
26
-
27
- function ensureOk(result, context) {
28
- const output = `${result.stdout || ""}\n${result.stderr || ""}`.trim();
29
- assert.strictEqual(result.status, 0, output || context);
30
- return output;
31
- }
32
-
33
- function initGitRepo(repo) {
34
- ensureOk(run("git", ["init"], repo), "git init failed");
35
- ensureOk(run("git", ["config", "user.email", "skills-smoke@example.com"], repo), "git config email failed");
36
- ensureOk(run("git", ["config", "user.name", "Skills Smoke"], repo), "git config name failed");
37
- ensureOk(run("git", ["add", "."], repo), "git add failed");
38
- ensureOk(run("git", ["commit", "-m", "skills smoke fixture"], repo), "git commit failed");
39
- }
40
-
41
- function buildIsolatedEnv(homeRoot) {
42
- const env = {
43
- HOME: homeRoot,
44
- USERPROFILE: homeRoot,
45
- APPDATA: path.join(homeRoot, "AppData", "Roaming"),
46
- LOCALAPPDATA: path.join(homeRoot, "AppData", "Local"),
47
- XDG_CONFIG_HOME: path.join(homeRoot, ".config"),
48
- };
49
- for (const value of Object.values(env)) {
50
- fs.mkdirSync(value, { recursive: true });
51
- }
52
- return env;
53
- }
54
-
55
- function findInstalledSkill(rootDir, skillName) {
56
- const matches = [];
57
-
58
- function walk(dir) {
59
- const entries = fs.readdirSync(dir, { withFileTypes: true });
60
- for (const entry of entries) {
61
- const fullPath = path.join(dir, entry.name);
62
- if (entry.isDirectory()) {
63
- walk(fullPath);
64
- continue;
65
- }
66
- if (entry.isFile() && entry.name === "SKILL.md" && path.basename(path.dirname(fullPath)) === skillName) {
67
- matches.push(path.dirname(fullPath));
68
- }
69
- }
70
- }
71
-
72
- walk(rootDir);
73
- return matches;
74
- }
75
-
76
- function main() {
77
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "trackops-skills-smoke-"));
78
- const sourceRepo = path.join(tempRoot, "source");
79
- const sourceSkillDir = path.join(sourceRepo, "skills", "trackops");
80
- const homeRoot = path.join(tempRoot, "home");
81
-
82
- fs.mkdirSync(path.dirname(sourceSkillDir), { recursive: true });
83
- fs.cpSync(SKILL_DIR, sourceSkillDir, { recursive: true });
84
- initGitRepo(sourceRepo);
85
-
86
- const env = buildIsolatedEnv(homeRoot);
87
- const distribution = SKILL_CONFIG.distribution || {};
88
- const skillName = distribution.skill || SKILL_CONFIG.name;
89
-
90
- const listResult = run(
91
- getNpxCommand(),
92
- ["--yes", "skills", "add", sourceRepo, "--list", "--skill", skillName, "--full-depth", "-y"],
93
- ROOT,
94
- env,
95
- );
96
- const listOutput = ensureOk(listResult, "skills list failed");
97
- assert.match(listOutput, /\btrackops\b/i, listOutput);
98
-
99
- const installResult = run(
100
- getNpxCommand(),
101
- ["--yes", "skills", "add", sourceRepo, "--skill", skillName, "--full-depth", "--global", "--agent", "codex", "--copy", "-y"],
102
- ROOT,
103
- env,
104
- );
105
- ensureOk(installResult, "skills install failed");
106
-
107
- const installed = findInstalledSkill(homeRoot, skillName);
108
- assert.ok(installed.length >= 1, `trackops skill was not installed under ${homeRoot}`);
109
-
110
- const installedSkillDir = installed[0];
111
- assert.ok(fs.existsSync(path.join(installedSkillDir, "references", "activation.md")));
112
- assert.ok(fs.existsSync(path.join(installedSkillDir, "skill.json")));
113
- assert.ok(!fs.existsSync(path.join(installedSkillDir, "scripts", "bootstrap-trackops.js")));
114
-
115
- fs.rmSync(tempRoot, { recursive: true, force: true });
116
- console.log("skills marketplace smoke OK");
117
- }
118
-
119
- try {
120
- main();
121
- } catch (error) {
122
- console.error(error.message);
123
- process.exit(1);
124
- }
1
+ #!/usr/bin/env node
2
+
3
+ const assert = require("assert");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const path = require("path");
7
+ const { spawnSync } = require("child_process");
8
+
9
+ const ROOT = path.resolve(__dirname, "..");
10
+ const SKILLS_ROOT = path.join(ROOT, "skills");
11
+ const REQUIRED_PUBLIC_SKILLS = ["trackops", "trackops-quality-guard"];
12
+
13
+ const REQUIRED_FILES_BY_SKILL = {
14
+ trackops: [
15
+ "references/activation.md",
16
+ "references/workflow.md",
17
+ "references/troubleshooting.md",
18
+ "skill.json",
19
+ ],
20
+ "trackops-quality-guard": [
21
+ "references/commands.md",
22
+ "references/decision-policy.md",
23
+ "references/output-format.md",
24
+ "skill.json",
25
+ ],
26
+ };
27
+
28
+ function run(command, args, cwd, envOverrides = {}) {
29
+ const shell = process.platform === "win32" && /\.(cmd|bat)$/i.test(command);
30
+ return spawnSync(command, args, {
31
+ cwd,
32
+ encoding: "utf8",
33
+ env: { ...process.env, ...envOverrides },
34
+ shell,
35
+ });
36
+ }
37
+
38
+ function getNpxCommand() {
39
+ return process.platform === "win32" ? "npx.cmd" : "npx";
40
+ }
41
+
42
+ function ensureOk(result, context) {
43
+ const output = `${result.stdout || ""}\n${result.stderr || ""}`.trim();
44
+ assert.strictEqual(result.status, 0, output || context);
45
+ return output;
46
+ }
47
+
48
+ function initGitRepo(repo) {
49
+ ensureOk(run("git", ["init"], repo), "git init failed");
50
+ ensureOk(run("git", ["config", "user.email", "skills-smoke@example.com"], repo), "git config email failed");
51
+ ensureOk(run("git", ["config", "user.name", "Skills Smoke"], repo), "git config name failed");
52
+ ensureOk(run("git", ["add", "."], repo), "git add failed");
53
+ ensureOk(run("git", ["commit", "-m", "skills smoke fixture"], repo), "git commit failed");
54
+ }
55
+
56
+ function buildIsolatedEnv(homeRoot) {
57
+ const env = {
58
+ HOME: homeRoot,
59
+ USERPROFILE: homeRoot,
60
+ APPDATA: path.join(homeRoot, "AppData", "Roaming"),
61
+ LOCALAPPDATA: path.join(homeRoot, "AppData", "Local"),
62
+ XDG_CONFIG_HOME: path.join(homeRoot, ".config"),
63
+ };
64
+ for (const value of Object.values(env)) {
65
+ fs.mkdirSync(value, { recursive: true });
66
+ }
67
+ return env;
68
+ }
69
+
70
+ function findInstalledSkill(rootDir, skillName) {
71
+ const matches = [];
72
+
73
+ function walk(dir) {
74
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
75
+ for (const entry of entries) {
76
+ const fullPath = path.join(dir, entry.name);
77
+ if (entry.isDirectory()) {
78
+ walk(fullPath);
79
+ continue;
80
+ }
81
+ if (entry.isFile() && entry.name === "SKILL.md" && path.basename(path.dirname(fullPath)) === skillName) {
82
+ matches.push(path.dirname(fullPath));
83
+ }
84
+ }
85
+ }
86
+
87
+ walk(rootDir);
88
+ return matches;
89
+ }
90
+
91
+ function discoverPublicSkills() {
92
+ return fs.readdirSync(SKILLS_ROOT, { withFileTypes: true })
93
+ .filter((entry) => entry.isDirectory() && fs.existsSync(path.join(SKILLS_ROOT, entry.name, "skill.json")))
94
+ .map((entry) => {
95
+ const dir = path.join(SKILLS_ROOT, entry.name);
96
+ const config = JSON.parse(fs.readFileSync(path.join(dir, "skill.json"), "utf8"));
97
+ return { name: entry.name, dir, config };
98
+ })
99
+ .sort((a, b) => a.name.localeCompare(b.name));
100
+ }
101
+
102
+ function main() {
103
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "trackops-skills-smoke-"));
104
+ const sourceRepo = path.join(tempRoot, "source");
105
+ const homeRoot = path.join(tempRoot, "home");
106
+
107
+ fs.mkdirSync(sourceRepo, { recursive: true });
108
+ fs.cpSync(SKILLS_ROOT, path.join(sourceRepo, "skills"), { recursive: true });
109
+ initGitRepo(sourceRepo);
110
+
111
+ const env = buildIsolatedEnv(homeRoot);
112
+ const skills = discoverPublicSkills();
113
+ for (const skillName of REQUIRED_PUBLIC_SKILLS) {
114
+ assert.ok(skills.some((entry) => entry.name === skillName), `missing public skill ${skillName}`);
115
+ }
116
+
117
+ for (const entry of skills) {
118
+ const distribution = entry.config.distribution || {};
119
+ const skillName = distribution.skill || entry.config.name;
120
+
121
+ const listResult = run(
122
+ getNpxCommand(),
123
+ ["--yes", "skills", "add", sourceRepo, "--list", "--skill", skillName, "--full-depth", "-y"],
124
+ ROOT,
125
+ env,
126
+ );
127
+ const listOutput = ensureOk(listResult, `skills list failed for ${skillName}`);
128
+ assert.ok(listOutput.includes(skillName), listOutput);
129
+
130
+ const installResult = run(
131
+ getNpxCommand(),
132
+ ["--yes", "skills", "add", sourceRepo, "--skill", skillName, "--full-depth", "--global", "--agent", "codex", "--copy", "-y"],
133
+ ROOT,
134
+ env,
135
+ );
136
+ ensureOk(installResult, `skills install failed for ${skillName}`);
137
+
138
+ const installed = findInstalledSkill(homeRoot, skillName);
139
+ assert.ok(installed.length >= 1, `${skillName} was not installed under ${homeRoot}`);
140
+
141
+ const installedSkillDir = installed[0];
142
+ for (const relativeFile of REQUIRED_FILES_BY_SKILL[skillName] || []) {
143
+ assert.ok(fs.existsSync(path.join(installedSkillDir, relativeFile)), `missing ${relativeFile} for ${skillName}`);
144
+ }
145
+ }
146
+
147
+ fs.rmSync(tempRoot, { recursive: true, force: true });
148
+ console.log("skills marketplace smoke OK");
149
+ }
150
+
151
+ try {
152
+ main();
153
+ } catch (error) {
154
+ console.error(error.message);
155
+ process.exit(1);
156
+ }