@boyingliu01/xp-gate 0.10.16 → 0.10.17
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/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/opencode/package.json +3 -3
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/opencode/tui-plugin.tsx +306 -0
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
- package/principles/AGENTS.md +3 -3
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
|
package/mutation/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MUTATION KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.17",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → SHIP → LAND → USER ACCEPTANCE → FEEDBACK → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boyingliu01/opencode-plugin",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"description": "XP-Gate quality gates + AI workflow skills + Sprint Flow TUI sidebar for OpenCode",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"types": "./index.ts"
|
|
20
20
|
},
|
|
21
21
|
"./tui": {
|
|
22
|
-
"import": "./tui-plugin.
|
|
23
|
-
"types": "./tui-plugin.
|
|
22
|
+
"import": "./tui-plugin.tsx",
|
|
23
|
+
"types": "./tui-plugin.tsx"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → SHIP → LAND → USER ACCEPTANCE → FEEDBACK → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// @no-test-required: TUI rendering plugin — tested via visual verification in OpenCode runtime
|
|
2
|
+
/**
|
|
3
|
+
* XP-Gate OpenCode TUI Slot Plugin
|
|
4
|
+
*
|
|
5
|
+
* Registers sidebar_content slot to display Sprint Flow progress
|
|
6
|
+
* from active sprint states discovered in .worktrees/sprint/ subdirectories.
|
|
7
|
+
*
|
|
8
|
+
* Rendered with @opentui/solid JSX — sidebar_content must return JSX.Element,
|
|
9
|
+
* NOT string (strings are silently ignored by OpenCode's TUI renderer).
|
|
10
|
+
*
|
|
11
|
+
* Users register this file in ~/.config/opencode/tui.json as:
|
|
12
|
+
* { "plugin": ["@boyingliu01/opencode-plugin/tui"] }
|
|
13
|
+
*/
|
|
14
|
+
/** @jsxImportSource @opentui/solid */
|
|
15
|
+
|
|
16
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs"
|
|
17
|
+
import { join, dirname, resolve, parse } from "node:path"
|
|
18
|
+
import { homedir } from "node:os"
|
|
19
|
+
import type { TuiPlugin, TuiSlotPlugin, TuiSlotProps } from "@opencode-ai/plugin/tui"
|
|
20
|
+
import { createMemo, Show, For } from "solid-js"
|
|
21
|
+
|
|
22
|
+
// ── Phase constants ──
|
|
23
|
+
|
|
24
|
+
const PHASE_NAMES: Record<string, string> = {
|
|
25
|
+
'-1': 'ISOLATE', '-0.5': 'AUTO-ESTIMATE', '0': 'THINK',
|
|
26
|
+
'1': 'PLAN', '2': 'BUILD', '3': 'REVIEW',
|
|
27
|
+
'4': 'SHIP', '5': 'LAND', '6': 'USER ACCEPT',
|
|
28
|
+
'7': 'FEEDBACK', '8': 'CLEANUP',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const PHASE_ORDER = ['-1', '-0.5', '0', '1', '2', '3', '4', '5', '6', '7', '8'];
|
|
32
|
+
|
|
33
|
+
// ── Types ──
|
|
34
|
+
|
|
35
|
+
interface SprintReq {
|
|
36
|
+
name?: string
|
|
37
|
+
status?: "completed" | "in_progress" | "pending"
|
|
38
|
+
}
|
|
39
|
+
interface SprintPhaseHistory {
|
|
40
|
+
phase: number | string
|
|
41
|
+
phase_name?: string
|
|
42
|
+
status?: "completed" | "in_progress" | "pending"
|
|
43
|
+
started_at?: string; completed_at?: string
|
|
44
|
+
duration_seconds?: number
|
|
45
|
+
reqs?: Record<string, SprintReq>
|
|
46
|
+
}
|
|
47
|
+
interface SprintState {
|
|
48
|
+
id?: string; phase?: number | string; status?: string; started_at?: string
|
|
49
|
+
task_description?: string
|
|
50
|
+
isolation?: { branch?: string; worktree_path?: string }
|
|
51
|
+
metrics?: { tests_passed?: number; tests_failed?: number; coverage_pct?: number }
|
|
52
|
+
phase_history?: SprintPhaseHistory[]
|
|
53
|
+
}
|
|
54
|
+
interface DiscoveredSprint {
|
|
55
|
+
state: SprintState; sourcePath: string; worktreeExists: boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Discovery ──
|
|
59
|
+
|
|
60
|
+
const MAX_DISCOVERY_RESULTS = 5;
|
|
61
|
+
|
|
62
|
+
function findGitRoot(startDir: string): string | null {
|
|
63
|
+
let current = resolve(startDir);
|
|
64
|
+
const root = parse(current).root;
|
|
65
|
+
const seen = new Set<string>();
|
|
66
|
+
while (current !== root) {
|
|
67
|
+
if (seen.has(current)) break;
|
|
68
|
+
seen.add(current);
|
|
69
|
+
if (existsSync(join(current, '.git'))) return current;
|
|
70
|
+
const parent = dirname(current);
|
|
71
|
+
if (parent === current) break;
|
|
72
|
+
current = parent;
|
|
73
|
+
}
|
|
74
|
+
if (existsSync(join(root, '.git'))) return root;
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function readSprintState(dir: string): SprintState | null {
|
|
79
|
+
try {
|
|
80
|
+
const sf = join(dir, '.sprint-state', 'sprint-state.json');
|
|
81
|
+
if (!existsSync(sf)) return null;
|
|
82
|
+
return JSON.parse(readFileSync(sf, 'utf8')) as SprintState;
|
|
83
|
+
} catch { return null; }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function checkWorktreeExists(p: string | undefined): boolean {
|
|
87
|
+
if (!p) return false;
|
|
88
|
+
try { return existsSync(p); } catch { return false; }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function parseTime(v: unknown): number {
|
|
92
|
+
return new Date(v as string).getTime();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isStaleSprint(s: SprintState | null): boolean {
|
|
96
|
+
if (!s?.started_at) return false;
|
|
97
|
+
let latest = parseTime(s.started_at);
|
|
98
|
+
if (isNaN(latest)) return false;
|
|
99
|
+
for (const ph of s.phase_history ?? []) {
|
|
100
|
+
if (ph.completed_at) latest = Math.max(latest, parseTime(ph.completed_at));
|
|
101
|
+
if (ph.started_at) latest = Math.max(latest, parseTime(ph.started_at));
|
|
102
|
+
}
|
|
103
|
+
return latest > 0 && Date.now() - latest > 3_600_000;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function discoverActiveSprints(dir: string): DiscoveredSprint[] {
|
|
107
|
+
const gitRoot = findGitRoot(dir);
|
|
108
|
+
const results: DiscoveredSprint[] = [];
|
|
109
|
+
|
|
110
|
+
if (gitRoot) {
|
|
111
|
+
const base = join(gitRoot, '.worktrees', 'sprint');
|
|
112
|
+
let entries: { name: string; isDirectory: () => boolean }[] = [];
|
|
113
|
+
try { if (existsSync(base)) entries = readdirSync(base, { withFileTypes: true }); } catch { /* ok */ }
|
|
114
|
+
for (const e of entries) {
|
|
115
|
+
if (!e.isDirectory()) continue;
|
|
116
|
+
const d = join(base, e.name);
|
|
117
|
+
const state = readSprintState(d);
|
|
118
|
+
if (!state?.id) continue;
|
|
119
|
+
const wt = checkWorktreeExists(d);
|
|
120
|
+
if (isStaleSprint(state) && !wt) continue;
|
|
121
|
+
results.push({ state, sourcePath: join(d, '.sprint-state', 'sprint-state.json'), worktreeExists: wt });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const localState = readSprintState(dir);
|
|
126
|
+
if (localState?.id) {
|
|
127
|
+
const wp = localState.isolation?.worktree_path;
|
|
128
|
+
const hasWp = !!wp;
|
|
129
|
+
const wt = hasWp ? checkWorktreeExists(wp) : false;
|
|
130
|
+
if (!hasWp || wt) results.push({ state: localState, sourcePath: join(dir, '.sprint-state', 'sprint-state.json'), worktreeExists: wt });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const deduped = new Map<string, DiscoveredSprint>();
|
|
134
|
+
for (const e of results) {
|
|
135
|
+
const id = e.state.id!;
|
|
136
|
+
const existing = deduped.get(id);
|
|
137
|
+
if (!existing) { deduped.set(id, e); continue; }
|
|
138
|
+
if (e.worktreeExists && !existing.worktreeExists) { deduped.set(id, e); continue; }
|
|
139
|
+
if (!e.worktreeExists && existing.worktreeExists) continue;
|
|
140
|
+
const eTs = e.state.started_at ? new Date(e.state.started_at).getTime() : 0;
|
|
141
|
+
const xTs = existing.state.started_at ? new Date(existing.state.started_at).getTime() : 0;
|
|
142
|
+
if (eTs > xTs || (eTs === xTs && e.sourcePath < existing.sourcePath)) deduped.set(id, e);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return Array.from(deduped.values())
|
|
146
|
+
.sort((a, b) => {
|
|
147
|
+
const aTs = a.state.started_at ? new Date(a.state.started_at).getTime() : 0;
|
|
148
|
+
const bTs = b.state.started_at ? new Date(b.state.started_at).getTime() : 0;
|
|
149
|
+
return bTs - aTs || String(b.state.id).localeCompare(String(a.state.id));
|
|
150
|
+
})
|
|
151
|
+
.slice(0, MAX_DISCOVERY_RESULTS);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Cache ──
|
|
155
|
+
|
|
156
|
+
let _cache: { data: DiscoveredSprint[]; upgradeNotice: string | null; ts: number; dir: string } | null = null;
|
|
157
|
+
const CACHE_TTL_MS = 5_000;
|
|
158
|
+
|
|
159
|
+
// ── Render helpers ──
|
|
160
|
+
|
|
161
|
+
function statusSymbol(status: string | undefined, currentPhase: string | number | undefined, key: string): string {
|
|
162
|
+
if (status === "completed") return "✓"
|
|
163
|
+
if (status === "in_progress") return "→"
|
|
164
|
+
if (String(currentPhase) === key) return "·"
|
|
165
|
+
return "○"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildPhaseLookup(state: SprintState): Record<string, SprintPhaseHistory> {
|
|
169
|
+
const lookup: Record<string, SprintPhaseHistory> = {}
|
|
170
|
+
for (const ph of state.phase_history ?? []) lookup[String(ph.phase)] = ph
|
|
171
|
+
return lookup
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function phaseLine(key: string, history: SprintPhaseHistory | undefined, currentPhase: string | number | undefined): string {
|
|
175
|
+
const name = history?.phase_name || PHASE_NAMES[key] || key
|
|
176
|
+
const st = history?.status || (String(currentPhase) === key ? "in_progress" : "pending")
|
|
177
|
+
const sym = statusSymbol(st, currentPhase, key)
|
|
178
|
+
const suffix = st === "completed" ? "done" : st === "in_progress" ? "active" : ""
|
|
179
|
+
return `${sym} ${name.padEnd(14)} ${suffix}`.replace(/\s+$/, "")
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function renderSprintTitle(state: SprintState): string {
|
|
183
|
+
if (state.task_description) return state.task_description;
|
|
184
|
+
if (state.id) {
|
|
185
|
+
const m = state.id.match(/sprint-(\d{4}-\d{2}-\d{2})-(\d+)/);
|
|
186
|
+
return m ? `Sprint ${m[1]} #${m[2]}` : state.id;
|
|
187
|
+
}
|
|
188
|
+
return 'Unknown Sprint';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ── Upgrade notice ──
|
|
192
|
+
|
|
193
|
+
const UPGRADE_NOTICE_FILE = join(homedir(), ".xp-gate", "upgrade-notice.json")
|
|
194
|
+
const UPGRADE_NOTICE_TTL_MS = 86_400_000
|
|
195
|
+
|
|
196
|
+
function readUpgradeNotice(): string | null {
|
|
197
|
+
try {
|
|
198
|
+
if (!existsSync(UPGRADE_NOTICE_FILE)) return null
|
|
199
|
+
const raw = JSON.parse(readFileSync(UPGRADE_NOTICE_FILE, "utf8"))
|
|
200
|
+
if (Date.now() - raw.ts < UPGRADE_NOTICE_TTL_MS && raw.message) {
|
|
201
|
+
const icon = raw.kind === "upgraded" ? "✓" : raw.kind === "outdated" ? "↑" : "⚠"
|
|
202
|
+
return `${icon} ${raw.message}`
|
|
203
|
+
}
|
|
204
|
+
return null
|
|
205
|
+
} catch { return null; }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ── JSX Components ──
|
|
209
|
+
|
|
210
|
+
function SprintCard(props: { sprint: DiscoveredSprint }) {
|
|
211
|
+
const { state } = props.sprint
|
|
212
|
+
const lookup = buildPhaseLookup(state)
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<box>
|
|
216
|
+
<text><b>SPRINT:</b> {renderSprintTitle(state)}</text>
|
|
217
|
+
<Show when={state.isolation?.branch}>
|
|
218
|
+
{(branch: () => string) => <text fg="#888888"> {branch()}</text>}
|
|
219
|
+
</Show>
|
|
220
|
+
<Show when={state.metrics?.tests_passed != null || state.metrics?.coverage_pct != null}>
|
|
221
|
+
<text fg="#888888">
|
|
222
|
+
{state.metrics?.tests_passed != null ? `tests:${state.metrics.tests_passed}` : ""}
|
|
223
|
+
{state.metrics?.coverage_pct != null ? ` cov:${state.metrics.coverage_pct}%` : ""}
|
|
224
|
+
</text>
|
|
225
|
+
</Show>
|
|
226
|
+
<Show when={isStaleSprint(state)}>
|
|
227
|
+
<text fg="#ffaa00"> ⚠ idle >1h</text>
|
|
228
|
+
</Show>
|
|
229
|
+
<For each={PHASE_ORDER}>
|
|
230
|
+
{(key: string) => {
|
|
231
|
+
const hist = lookup[key]
|
|
232
|
+
if (!hist && String(state.phase) !== key) return null
|
|
233
|
+
return <text>{phaseLine(key, hist, state.phase)}</text>
|
|
234
|
+
}}
|
|
235
|
+
</For>
|
|
236
|
+
</box>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function SprintSidebar(props: { sprints: DiscoveredSprint[] }) {
|
|
241
|
+
const display = props.sprints.slice(0, 3)
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<box>
|
|
245
|
+
<For each={display}>
|
|
246
|
+
{(sprint: DiscoveredSprint, i: () => number) => (
|
|
247
|
+
<>
|
|
248
|
+
<Show when={i() > 0}>
|
|
249
|
+
<text>---</text>
|
|
250
|
+
</Show>
|
|
251
|
+
<SprintCard sprint={sprint} />
|
|
252
|
+
</>
|
|
253
|
+
)}
|
|
254
|
+
</For>
|
|
255
|
+
<Show when={props.sprints.length > 3}>
|
|
256
|
+
<text>... +{props.sprints.length - 3} more</text>
|
|
257
|
+
</Show>
|
|
258
|
+
</box>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function renderContent(sprints: DiscoveredSprint[], upgradeNotice: string | null, dir: string) {
|
|
263
|
+
const components: any[] = []
|
|
264
|
+
|
|
265
|
+
if (sprints.length > 0) {
|
|
266
|
+
if (upgradeNotice) components.push(<text>{upgradeNotice}</text>)
|
|
267
|
+
components.push(<SprintSidebar sprints={sprints} />)
|
|
268
|
+
return components.length > 1 ? <box>{components}</box> : components[0]
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const hasStateDir = existsSync(join(dir, ".sprint-state"))
|
|
272
|
+
const gitRoot = findGitRoot(dir)
|
|
273
|
+
const hasWorktreesRoot = gitRoot ? existsSync(join(gitRoot, ".worktrees")) : false
|
|
274
|
+
|
|
275
|
+
if (hasStateDir) return <box>{upgradeNotice ? <text>{upgradeNotice}</text> : null}<text><b>SPRINT FLOW</b></text><text> -> Initializing...</text></box>
|
|
276
|
+
if (hasWorktreesRoot) return <box>{upgradeNotice ? <text>{upgradeNotice}</text> : null}<text><b>SPRINT FLOW</b></text><text> · Ready...</text></box>
|
|
277
|
+
if (upgradeNotice) return <box><text>{upgradeNotice}</text></box>
|
|
278
|
+
|
|
279
|
+
return null
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ── TUI Slot Plugin ──
|
|
283
|
+
|
|
284
|
+
const tuiPlugin: TuiSlotPlugin = {
|
|
285
|
+
slots: {
|
|
286
|
+
sidebar_content: (_props: TuiSlotProps) => {
|
|
287
|
+
const dir = process.env.XP_GATE_PROJECT_DIR || process.cwd();
|
|
288
|
+
const now = Date.now();
|
|
289
|
+
|
|
290
|
+
if (_cache && _cache.dir === dir && now - _cache.ts < CACHE_TTL_MS) {
|
|
291
|
+
return renderContent(_cache.data, _cache.upgradeNotice, dir);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const sprints = discoverActiveSprints(dir);
|
|
295
|
+
const upgradeNotice = readUpgradeNotice()
|
|
296
|
+
_cache = { data: sprints, ts: now, dir, upgradeNotice };
|
|
297
|
+
return renderContent(sprints, upgradeNotice, dir);
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const plugin: TuiPlugin = async (api, _options, _meta) => {
|
|
303
|
+
api.slots.register(tuiPlugin)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { plugin as tui, readSprintState }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.17",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/principles/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# PRINCIPLES CHECKER MODULE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → SHIP → LAND → USER ACCEPTANCE → FEEDBACK → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-26
|
|
4
|
+
**Commit:** afab469
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.17.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|