@boyingliu01/xp-gate 0.15.4 → 0.15.5

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 (72) hide show
  1. package/adapter-common.sh +0 -0
  2. package/adapters/cpp.sh +0 -0
  3. package/adapters/dart.sh +0 -0
  4. package/adapters/flutter.sh +0 -0
  5. package/adapters/gate-3.sh +68 -0
  6. package/adapters/gate-4.sh +80 -0
  7. package/adapters/gate-7.sh +45 -0
  8. package/adapters/gate-8.sh +56 -0
  9. package/adapters/gate-9.sh +104 -0
  10. package/adapters/go.sh +0 -0
  11. package/adapters/iac.sh +0 -0
  12. package/adapters/java.sh +0 -0
  13. package/adapters/kotlin.sh +0 -0
  14. package/adapters/objectivec.sh +0 -0
  15. package/adapters/plugins/book299-20132-python/scripts/install-gradle.sh +0 -0
  16. package/adapters/plugins/book299-20132-python/scripts/install-maven.sh +0 -0
  17. package/adapters/plugins/book299-4081-c/scripts/install-gradle.sh +0 -0
  18. package/adapters/plugins/book299-4081-c/scripts/install-maven.sh +0 -0
  19. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-gradle.sh +0 -0
  20. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-maven.sh +0 -0
  21. package/adapters/powershell.sh +0 -0
  22. package/adapters/python.sh +0 -0
  23. package/adapters/shell.sh +0 -0
  24. package/adapters/swift.sh +0 -0
  25. package/adapters/typescript.sh +0 -0
  26. package/bin/xp-gate.js +0 -0
  27. package/gate-3.sh +0 -0
  28. package/gate-4.sh +0 -0
  29. package/gate-7.sh +0 -0
  30. package/gate-8.sh +0 -0
  31. package/gate-9.sh +0 -0
  32. package/hooks/adapter-common.sh +0 -0
  33. package/hooks/gate-3.sh +0 -0
  34. package/hooks/gate-4.sh +0 -0
  35. package/hooks/gate-7.sh +0 -0
  36. package/hooks/gate-8.sh +0 -0
  37. package/hooks/gate-9.sh +0 -0
  38. package/hooks/pre-commit +0 -0
  39. package/hooks/pre-push +0 -0
  40. package/lib/__tests__/phase-transition.test.js +272 -272
  41. package/lib/__tests__/sprint-audit.test.js +207 -207
  42. package/lib/doctor-tui.js +198 -198
  43. package/lib/language-tools.js +833 -833
  44. package/lib/phase-transition.js +249 -249
  45. package/lib/sprint-audit.js +235 -235
  46. package/mock-policy/AGENTS.md +2 -2
  47. package/mutation/AGENTS.md +2 -2
  48. package/package.json +1 -1
  49. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  50. package/plugins/claude-code/bin/delphi-review-guard.sh +0 -0
  51. package/plugins/claude-code/bin/xp-gate-check +0 -0
  52. package/plugins/claude-code/skills/delphi-review/AGENTS.md +2 -2
  53. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +2 -2
  54. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +2 -2
  55. package/plugins/opencode/package.json +1 -1
  56. package/plugins/opencode/skills/delphi-review/AGENTS.md +2 -2
  57. package/plugins/opencode/skills/sprint-flow/AGENTS.md +2 -2
  58. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +2 -2
  59. package/plugins/qoder/agents/delphi-architecture.md +48 -48
  60. package/plugins/qoder/agents/delphi-feasibility.md +48 -48
  61. package/plugins/qoder/agents/delphi-technical.md +48 -48
  62. package/plugins/qoder/bin/sprint-flow-guard.sh +0 -0
  63. package/plugins/qoder/bin/xp-gate-check +0 -0
  64. package/plugins/qoder/plugin.json +1 -1
  65. package/plugins/qoder/skills/delphi-review/AGENTS.md +2 -2
  66. package/plugins/qoder/skills/sprint-flow/AGENTS.md +2 -2
  67. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +2 -2
  68. package/principles/AGENTS.md +2 -2
  69. package/scripts/delphi-external-review.cjs +432 -432
  70. package/skills/delphi-review/AGENTS.md +2 -2
  71. package/skills/sprint-flow/AGENTS.md +2 -2
  72. package/skills/test-specification-alignment/AGENTS.md +2 -2
package/lib/doctor-tui.js CHANGED
@@ -1,198 +1,198 @@
1
- /**
2
- * TUI registration and installed-skills diagnostics for doctor.
3
- * Extracted from doctor.js to keep file size under the large-file threshold.
4
- */
5
- const fs = require('fs');
6
- const path = require('path');
7
- const { HOME_DIR, detectPlatform } = require('./shared-paths.js');
8
-
9
- // npm package source dir (template hooks/adapters)
10
- const PKG_DIR = path.dirname(__dirname);
11
-
12
- /**
13
- * TUI registration path and expected plugin entry.
14
- */
15
- const TUI_JSON_PATH = path.join(HOME_DIR, '.config', 'opencode', 'tui.json');
16
- const TUI_PLUGIN_ENTRY = '@boyingliu01/opencode-plugin/tui';
17
-
18
- /**
19
- * Read and parse tui.json, returning { data, error }.
20
- * data = parsed object on success, null on file missing, undefined on corrupt.
21
- */
22
- function readTuiJson() {
23
- if (!fs.existsSync(TUI_JSON_PATH)) return { data: null, error: null };
24
- try {
25
- const raw = fs.readFileSync(TUI_JSON_PATH, 'utf8');
26
- const data = JSON.parse(raw);
27
- return { data, error: null };
28
- } catch (e) {
29
- return { data: undefined, error: `Corrupt JSON: ${e.message}` };
30
- }
31
- }
32
-
33
- /**
34
- * Check 9: TUI auto-registration in ~/.config/opencode/tui.json.
35
- * @returns {number} issue count
36
- */
37
- function diagnoseTuiRegistration(checks) {
38
- const { data, error } = readTuiJson();
39
-
40
- if (error) {
41
- checks.push({ name: 'TUI registration', status: 'FAIL', detail: error });
42
- return 1;
43
- }
44
-
45
- if (data === null) {
46
- checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
47
- return 1;
48
- }
49
-
50
- const plugins = Array.isArray(data.plugin) ? data.plugin : [];
51
- if (plugins.includes(TUI_PLUGIN_ENTRY)) {
52
- checks.push({ name: 'TUI registration', status: 'PASS', detail: `${TUI_PLUGIN_ENTRY} registered` });
53
- return 0;
54
- }
55
-
56
- checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
57
- return 1;
58
- }
59
-
60
- /**
61
- * Check 9: Installed skills vs package-bundled skills (#332).
62
- * Reports WARN for each installed skill whose SKILL.md differs from the bundled version.
63
- * @param {object} config
64
- * @param {Array} checks
65
- * @returns {number} issue count
66
- */
67
- function diagnoseInstalledSkills(config, checks) {
68
- const installedSkills = config.installedSkills || {};
69
- const skillNames = Object.keys(installedSkills);
70
- if (skillNames.length === 0) {
71
- checks.push({ name: 'Installed skills', status: 'SKIP', detail: 'No skills installed' });
72
- return 0;
73
- }
74
-
75
- const bundledSkillsDir = path.join(PKG_DIR, 'skills');
76
- if (!fs.existsSync(bundledSkillsDir)) {
77
- checks.push({ name: 'Installed skills', status: 'SKIP', detail: 'Package skills dir not found' });
78
- return 0;
79
- }
80
-
81
- const platform = detectPlatform();
82
- let userSkillsDir;
83
- if (platform === 'qoder') {
84
- userSkillsDir = path.join(HOME_DIR, '.qoder', 'skills');
85
- } else if (platform === 'claude-code') {
86
- userSkillsDir = path.join(HOME_DIR, '.claude', 'skills');
87
- } else {
88
- userSkillsDir = path.join(HOME_DIR, '.config', 'opencode', 'skills');
89
- }
90
-
91
- let issues = 0;
92
- for (const name of skillNames) {
93
- const bundledSkillMd = path.join(bundledSkillsDir, name, 'SKILL.md');
94
- const userSkillMd = path.join(userSkillsDir, name, 'SKILL.md');
95
-
96
- if (!fs.existsSync(bundledSkillMd)) continue;
97
- if (!fs.existsSync(userSkillMd)) {
98
- checks.push({ name: `Skill: ${name}`, status: 'FAIL', detail: 'Installed SKILL.md missing' });
99
- issues++;
100
- continue;
101
- }
102
-
103
- const bundledContent = fs.readFileSync(bundledSkillMd, 'utf8');
104
- const userContent = fs.readFileSync(userSkillMd, 'utf8');
105
- if (bundledContent !== userContent) {
106
- checks.push({
107
- name: `Skill: ${name}`,
108
- status: 'WARN',
109
- detail: 'Outdated — run xp-gate update-skill --all',
110
- });
111
- issues++;
112
- } else {
113
- checks.push({ name: `Skill: ${name}`, status: 'PASS', detail: 'Up to date' });
114
- }
115
- }
116
-
117
- return issues;
118
- }
119
-
120
- /**
121
- * Fix TUI registration: ensure @boyingliu01/opencode-plugin/tui is in tui.json.
122
- * Uses atomic write (tmp + renameSync) for JSON safety.
123
- * On corrupt JSON: backup to .corrupt-{timestamp}.bak then rebuild.
124
- * Idempotent: skips if already registered.
125
- * @returns {boolean} Whether a fix was applied
126
- */
127
- function fixTuiRegistration() {
128
- const { data, error } = readTuiJson();
129
-
130
- // Corrupt JSON: backup old file, rebuild from scratch
131
- if (error && data === undefined) {
132
- const ts = Date.now();
133
- const backupPath = `${TUI_JSON_PATH}.corrupt-${ts}.bak`;
134
- try {
135
- fs.copyFileSync(TUI_JSON_PATH, backupPath);
136
- console.log(` ⚠ TUI config corrupted — backed up to ${backupPath}`);
137
- } catch { /* non-critical */ }
138
- // Rebuild fresh
139
- const dir = path.dirname(TUI_JSON_PATH);
140
- fs.mkdirSync(dir, { recursive: true });
141
- const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
142
- const tmpPath = `${TUI_JSON_PATH}.tmp`;
143
- fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
144
- fs.renameSync(tmpPath, TUI_JSON_PATH);
145
- console.log(` ✓ Registered ${TUI_PLUGIN_ENTRY} in TUI (rebuilt after corrupt backup)`);
146
- return true;
147
- }
148
-
149
- // File doesn't exist: create it
150
- if (data === null) {
151
- const dir = path.dirname(TUI_JSON_PATH);
152
- fs.mkdirSync(dir, { recursive: true });
153
- const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
154
- const tmpPath = `${TUI_JSON_PATH}.tmp`;
155
- fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
156
- fs.renameSync(tmpPath, TUI_JSON_PATH);
157
- console.log(` ✓ Created TUI config with ${TUI_PLUGIN_ENTRY}`);
158
- return true;
159
- }
160
-
161
- // File exists, check if plugin already registered (idempotent)
162
- const plugins = Array.isArray(data.plugin) ? data.plugin : [];
163
- if (plugins.includes(TUI_PLUGIN_ENTRY)) return false;
164
-
165
- // Append plugin entry
166
- data.plugin = plugins.concat([TUI_PLUGIN_ENTRY]);
167
- const tmpPath = `${TUI_JSON_PATH}.tmp`;
168
- fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
169
- fs.renameSync(tmpPath, TUI_JSON_PATH);
170
- console.log(` ✓ Added ${TUI_PLUGIN_ENTRY} to TUI config`);
171
- return true;
172
- }
173
-
174
- /**
175
- * Wrapper for init.js: ensure TUI is registered without console output.
176
- * Returns true if the plugin is already registered or was just added.
177
- */
178
- function ensureTuiRegistration() {
179
- const { data } = readTuiJson();
180
- if (data === null || data === undefined) {
181
- fixTuiRegistration();
182
- return;
183
- }
184
- const plugins = Array.isArray(data.plugin) ? data.plugin : [];
185
- if (!plugins.includes(TUI_PLUGIN_ENTRY)) {
186
- fixTuiRegistration();
187
- }
188
- }
189
-
190
- module.exports = {
191
- TUI_JSON_PATH,
192
- TUI_PLUGIN_ENTRY,
193
- readTuiJson,
194
- diagnoseTuiRegistration,
195
- diagnoseInstalledSkills,
196
- fixTuiRegistration,
197
- ensureTuiRegistration,
198
- };
1
+ /**
2
+ * TUI registration and installed-skills diagnostics for doctor.
3
+ * Extracted from doctor.js to keep file size under the large-file threshold.
4
+ */
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { HOME_DIR, detectPlatform } = require('./shared-paths.js');
8
+
9
+ // npm package source dir (template hooks/adapters)
10
+ const PKG_DIR = path.dirname(__dirname);
11
+
12
+ /**
13
+ * TUI registration path and expected plugin entry.
14
+ */
15
+ const TUI_JSON_PATH = path.join(HOME_DIR, '.config', 'opencode', 'tui.json');
16
+ const TUI_PLUGIN_ENTRY = '@boyingliu01/opencode-plugin/tui';
17
+
18
+ /**
19
+ * Read and parse tui.json, returning { data, error }.
20
+ * data = parsed object on success, null on file missing, undefined on corrupt.
21
+ */
22
+ function readTuiJson() {
23
+ if (!fs.existsSync(TUI_JSON_PATH)) return { data: null, error: null };
24
+ try {
25
+ const raw = fs.readFileSync(TUI_JSON_PATH, 'utf8');
26
+ const data = JSON.parse(raw);
27
+ return { data, error: null };
28
+ } catch (e) {
29
+ return { data: undefined, error: `Corrupt JSON: ${e.message}` };
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Check 9: TUI auto-registration in ~/.config/opencode/tui.json.
35
+ * @returns {number} issue count
36
+ */
37
+ function diagnoseTuiRegistration(checks) {
38
+ const { data, error } = readTuiJson();
39
+
40
+ if (error) {
41
+ checks.push({ name: 'TUI registration', status: 'FAIL', detail: error });
42
+ return 1;
43
+ }
44
+
45
+ if (data === null) {
46
+ checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
47
+ return 1;
48
+ }
49
+
50
+ const plugins = Array.isArray(data.plugin) ? data.plugin : [];
51
+ if (plugins.includes(TUI_PLUGIN_ENTRY)) {
52
+ checks.push({ name: 'TUI registration', status: 'PASS', detail: `${TUI_PLUGIN_ENTRY} registered` });
53
+ return 0;
54
+ }
55
+
56
+ checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
57
+ return 1;
58
+ }
59
+
60
+ /**
61
+ * Check 9: Installed skills vs package-bundled skills (#332).
62
+ * Reports WARN for each installed skill whose SKILL.md differs from the bundled version.
63
+ * @param {object} config
64
+ * @param {Array} checks
65
+ * @returns {number} issue count
66
+ */
67
+ function diagnoseInstalledSkills(config, checks) {
68
+ const installedSkills = config.installedSkills || {};
69
+ const skillNames = Object.keys(installedSkills);
70
+ if (skillNames.length === 0) {
71
+ checks.push({ name: 'Installed skills', status: 'SKIP', detail: 'No skills installed' });
72
+ return 0;
73
+ }
74
+
75
+ const bundledSkillsDir = path.join(PKG_DIR, 'skills');
76
+ if (!fs.existsSync(bundledSkillsDir)) {
77
+ checks.push({ name: 'Installed skills', status: 'SKIP', detail: 'Package skills dir not found' });
78
+ return 0;
79
+ }
80
+
81
+ const platform = detectPlatform();
82
+ let userSkillsDir;
83
+ if (platform === 'qoder') {
84
+ userSkillsDir = path.join(HOME_DIR, '.qoder', 'skills');
85
+ } else if (platform === 'claude-code') {
86
+ userSkillsDir = path.join(HOME_DIR, '.claude', 'skills');
87
+ } else {
88
+ userSkillsDir = path.join(HOME_DIR, '.config', 'opencode', 'skills');
89
+ }
90
+
91
+ let issues = 0;
92
+ for (const name of skillNames) {
93
+ const bundledSkillMd = path.join(bundledSkillsDir, name, 'SKILL.md');
94
+ const userSkillMd = path.join(userSkillsDir, name, 'SKILL.md');
95
+
96
+ if (!fs.existsSync(bundledSkillMd)) continue;
97
+ if (!fs.existsSync(userSkillMd)) {
98
+ checks.push({ name: `Skill: ${name}`, status: 'FAIL', detail: 'Installed SKILL.md missing' });
99
+ issues++;
100
+ continue;
101
+ }
102
+
103
+ const bundledContent = fs.readFileSync(bundledSkillMd, 'utf8');
104
+ const userContent = fs.readFileSync(userSkillMd, 'utf8');
105
+ if (bundledContent !== userContent) {
106
+ checks.push({
107
+ name: `Skill: ${name}`,
108
+ status: 'WARN',
109
+ detail: 'Outdated — run xp-gate update-skill --all',
110
+ });
111
+ issues++;
112
+ } else {
113
+ checks.push({ name: `Skill: ${name}`, status: 'PASS', detail: 'Up to date' });
114
+ }
115
+ }
116
+
117
+ return issues;
118
+ }
119
+
120
+ /**
121
+ * Fix TUI registration: ensure @boyingliu01/opencode-plugin/tui is in tui.json.
122
+ * Uses atomic write (tmp + renameSync) for JSON safety.
123
+ * On corrupt JSON: backup to .corrupt-{timestamp}.bak then rebuild.
124
+ * Idempotent: skips if already registered.
125
+ * @returns {boolean} Whether a fix was applied
126
+ */
127
+ function fixTuiRegistration() {
128
+ const { data, error } = readTuiJson();
129
+
130
+ // Corrupt JSON: backup old file, rebuild from scratch
131
+ if (error && data === undefined) {
132
+ const ts = Date.now();
133
+ const backupPath = `${TUI_JSON_PATH}.corrupt-${ts}.bak`;
134
+ try {
135
+ fs.copyFileSync(TUI_JSON_PATH, backupPath);
136
+ console.log(` ⚠ TUI config corrupted — backed up to ${backupPath}`);
137
+ } catch { /* non-critical */ }
138
+ // Rebuild fresh
139
+ const dir = path.dirname(TUI_JSON_PATH);
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
142
+ const tmpPath = `${TUI_JSON_PATH}.tmp`;
143
+ fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
144
+ fs.renameSync(tmpPath, TUI_JSON_PATH);
145
+ console.log(` ✓ Registered ${TUI_PLUGIN_ENTRY} in TUI (rebuilt after corrupt backup)`);
146
+ return true;
147
+ }
148
+
149
+ // File doesn't exist: create it
150
+ if (data === null) {
151
+ const dir = path.dirname(TUI_JSON_PATH);
152
+ fs.mkdirSync(dir, { recursive: true });
153
+ const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
154
+ const tmpPath = `${TUI_JSON_PATH}.tmp`;
155
+ fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
156
+ fs.renameSync(tmpPath, TUI_JSON_PATH);
157
+ console.log(` ✓ Created TUI config with ${TUI_PLUGIN_ENTRY}`);
158
+ return true;
159
+ }
160
+
161
+ // File exists, check if plugin already registered (idempotent)
162
+ const plugins = Array.isArray(data.plugin) ? data.plugin : [];
163
+ if (plugins.includes(TUI_PLUGIN_ENTRY)) return false;
164
+
165
+ // Append plugin entry
166
+ data.plugin = plugins.concat([TUI_PLUGIN_ENTRY]);
167
+ const tmpPath = `${TUI_JSON_PATH}.tmp`;
168
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
169
+ fs.renameSync(tmpPath, TUI_JSON_PATH);
170
+ console.log(` ✓ Added ${TUI_PLUGIN_ENTRY} to TUI config`);
171
+ return true;
172
+ }
173
+
174
+ /**
175
+ * Wrapper for init.js: ensure TUI is registered without console output.
176
+ * Returns true if the plugin is already registered or was just added.
177
+ */
178
+ function ensureTuiRegistration() {
179
+ const { data } = readTuiJson();
180
+ if (data === null || data === undefined) {
181
+ fixTuiRegistration();
182
+ return;
183
+ }
184
+ const plugins = Array.isArray(data.plugin) ? data.plugin : [];
185
+ if (!plugins.includes(TUI_PLUGIN_ENTRY)) {
186
+ fixTuiRegistration();
187
+ }
188
+ }
189
+
190
+ module.exports = {
191
+ TUI_JSON_PATH,
192
+ TUI_PLUGIN_ENTRY,
193
+ readTuiJson,
194
+ diagnoseTuiRegistration,
195
+ diagnoseInstalledSkills,
196
+ fixTuiRegistration,
197
+ ensureTuiRegistration,
198
+ };