@boyingliu01/xp-gate 0.9.3 → 0.9.4
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/lib/__tests__/baseline.test.js +89 -0
- package/lib/__tests__/doctor-helpers.test.js +139 -0
- package/lib/__tests__/upgrade-exec.test.js +42 -33
- package/lib/baseline.js +75 -48
- package/lib/doctor.js +180 -93
- package/lib/install-skill.js +81 -62
- package/lib/shared-phase-constants.d.ts +17 -0
- package/lib/shared-phase-constants.js +63 -0
- package/lib/shared-utils.js +14 -3
- package/lib/sprint-status.js +75 -83
- package/lib/upgrade.js +128 -85
- 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/__tests__/xp-gate-update.test.ts +133 -4
- package/plugins/opencode/index.ts +28 -3
- package/plugins/opencode/package.json +1 -1
- 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.ts +44 -75
- 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
|
@@ -14,7 +14,8 @@ import { randomUUID } from "node:crypto"
|
|
|
14
14
|
import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from "node:fs"
|
|
15
15
|
import { join } from "node:path"
|
|
16
16
|
import { tmpdir, homedir } from "node:os"
|
|
17
|
-
import { execSync } from "node:child_process"
|
|
17
|
+
import { execSync, spawn } from "node:child_process"
|
|
18
|
+
import { EventEmitter } from "node:events"
|
|
18
19
|
|
|
19
20
|
// ── Pure function: semverLt ──
|
|
20
21
|
|
|
@@ -153,14 +154,19 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
153
154
|
return { action: "noop", localVersion, remoteVersion }
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
// 5. Outdated — auto upgrade
|
|
157
|
+
// 5. Outdated — auto upgrade (non-blocking spawn)
|
|
157
158
|
writeXpGateCache({ ts: Date.now(), localVersion, remoteVersion })
|
|
158
159
|
try {
|
|
159
|
-
|
|
160
|
+
const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
|
|
160
161
|
stdio: "pipe",
|
|
161
162
|
timeout: 120_000,
|
|
162
163
|
})
|
|
163
|
-
|
|
164
|
+
child.on("close", (code) => {
|
|
165
|
+
if (code === 0) {
|
|
166
|
+
writeXpGateCache({ ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
|
|
164
170
|
return { action: "upgraded", localVersion, remoteVersion }
|
|
165
171
|
} catch (err) {
|
|
166
172
|
const msg = err instanceof Error ? err.message : String(err)
|
|
@@ -168,6 +174,31 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
168
174
|
}
|
|
169
175
|
}
|
|
170
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Read xp-gate config.json for opt-out settings.
|
|
179
|
+
* Returns null if config doesn't exist or is malformed.
|
|
180
|
+
*/
|
|
181
|
+
function readXpGateConfig(): { autoUpgrade?: boolean } | null {
|
|
182
|
+
const cfgPath = join(homedir(), ".xp-gate", "config.json")
|
|
183
|
+
try {
|
|
184
|
+
if (!existsSync(cfgPath)) return null
|
|
185
|
+
const raw = readFileSync(cfgPath, "utf8")
|
|
186
|
+
return JSON.parse(raw)
|
|
187
|
+
} catch {
|
|
188
|
+
return null
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Wait for a child process to close and resolve with exit code.
|
|
194
|
+
*/
|
|
195
|
+
function waitForSpawn(child: ReturnType<typeof spawn>): Promise<number> {
|
|
196
|
+
return new Promise((resolve, reject) => {
|
|
197
|
+
child.on("close", (code) => resolve(code ?? -1))
|
|
198
|
+
child.on("error", (err) => reject(err))
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
171
202
|
// ── Tests ──
|
|
172
203
|
|
|
173
204
|
void describe("semverLt", () => {
|
|
@@ -253,3 +284,101 @@ void describe("checkXpGateUpdate — cache & upgrade", () => {
|
|
|
253
284
|
assert.equal(result.action, "noop")
|
|
254
285
|
})
|
|
255
286
|
})
|
|
287
|
+
|
|
288
|
+
// ── UPG-002: spawn-based upgrade tests ──
|
|
289
|
+
|
|
290
|
+
void describe("checkXpGateUpdate — spawn (UPG-002)", () => {
|
|
291
|
+
const fakeHome = join(tmpdir(), "xp-gate-upd-spawn-" + randomUUID())
|
|
292
|
+
const origHome = process.env.HOME
|
|
293
|
+
|
|
294
|
+
before(() => {
|
|
295
|
+
process.env.HOME = fakeHome
|
|
296
|
+
mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
after(() => {
|
|
300
|
+
process.env.HOME = origHome
|
|
301
|
+
rmSync(fakeHome, { recursive: true, force: true })
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
void it("returns upgraded with spawn-based npm install", async () => {
|
|
305
|
+
const cachePath = join(fakeHome, ".xp-gate", "xp-gate-version-check.json")
|
|
306
|
+
writeFileSync(cachePath, JSON.stringify({
|
|
307
|
+
ts: Date.now() - 86_400_000 - 3600_000, // stale
|
|
308
|
+
localVersion: "0.9.1",
|
|
309
|
+
remoteVersion: "0.9.2",
|
|
310
|
+
}))
|
|
311
|
+
|
|
312
|
+
const result = await checkXpGateUpdate()
|
|
313
|
+
assert.ok(["noop", "upgraded", "error"].includes(result.action))
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
// ── UPG-003: readXpGateConfig isolated tests ──
|
|
318
|
+
|
|
319
|
+
void describe("readXpGateConfig", () => {
|
|
320
|
+
const fakeHome = join(tmpdir(), "xp-gate-upd-cfg-" + randomUUID())
|
|
321
|
+
const origHome = process.env.HOME
|
|
322
|
+
|
|
323
|
+
before(() => {
|
|
324
|
+
process.env.HOME = fakeHome
|
|
325
|
+
mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
after(() => {
|
|
329
|
+
process.env.HOME = origHome
|
|
330
|
+
rmSync(fakeHome, { recursive: true, force: true })
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
void it("returns null when no config.json exists", () => {
|
|
334
|
+
assert.equal(readXpGateConfig(), null)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
void it("returns parsed config when config.json exists with autoUpgrade false", () => {
|
|
338
|
+
const cfgPath = join(fakeHome, ".xp-gate", "config.json")
|
|
339
|
+
writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: false }))
|
|
340
|
+
const cfg = readXpGateConfig()
|
|
341
|
+
assert.notEqual(cfg, null)
|
|
342
|
+
assert.equal(cfg!.autoUpgrade, false)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
void it("returns parsed config when config.json exists with autoUpgrade true", () => {
|
|
346
|
+
const cfgPath = join(fakeHome, ".xp-gate", "config.json")
|
|
347
|
+
writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: true }))
|
|
348
|
+
const cfg = readXpGateConfig()
|
|
349
|
+
assert.notEqual(cfg, null)
|
|
350
|
+
assert.equal(cfg!.autoUpgrade, true)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
void it("returns null when config.json is malformed", () => {
|
|
354
|
+
const cfgPath = join(fakeHome, ".xp-gate", "config.json")
|
|
355
|
+
writeFileSync(cfgPath, "not-json")
|
|
356
|
+
assert.equal(readXpGateConfig(), null)
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
// ── UPG-003: opt-out config integration tests ──
|
|
361
|
+
|
|
362
|
+
void describe("checkXpGateUpdate — opt-out config integration (UPG-003)", () => {
|
|
363
|
+
const fakeHome = join(tmpdir(), "xp-gate-upd-cfg-int-" + randomUUID())
|
|
364
|
+
const origHome = process.env.HOME
|
|
365
|
+
|
|
366
|
+
before(() => {
|
|
367
|
+
process.env.HOME = fakeHome
|
|
368
|
+
mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
after(() => {
|
|
372
|
+
process.env.HOME = origHome
|
|
373
|
+
rmSync(fakeHome, { recursive: true, force: true })
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
void it("handles config.json with autoUpgrade false (no crash, graceful noop)", async () => {
|
|
377
|
+
const cfgPath = join(fakeHome, ".xp-gate", "config.json")
|
|
378
|
+
writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: false }))
|
|
379
|
+
|
|
380
|
+
const result = await checkXpGateUpdate()
|
|
381
|
+
// Should not crash — returns noop because local install not found in fake home
|
|
382
|
+
assert.ok(["noop", "upgraded", "error"].includes(result.action))
|
|
383
|
+
})
|
|
384
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin"
|
|
2
2
|
import { z } from "zod"
|
|
3
|
-
import { exec, execSync } from "node:child_process"
|
|
3
|
+
import { exec, execSync, spawn } from "node:child_process"
|
|
4
4
|
import { promisify } from "node:util"
|
|
5
5
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from "node:fs"
|
|
6
6
|
import { join } from "node:path"
|
|
@@ -115,10 +115,25 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
115
115
|
return { action: "noop", localVersion, remoteVersion }
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
// Check opt-out config
|
|
119
|
+
const config = readXpGateConfig()
|
|
120
|
+
if (config?.autoUpgrade === false) {
|
|
121
|
+
writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion, remoteVersion, status: "current" })
|
|
122
|
+
return { action: "noop", localVersion, remoteVersion }
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion, remoteVersion })
|
|
119
126
|
try {
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
|
|
128
|
+
stdio: "pipe",
|
|
129
|
+
timeout: 120_000,
|
|
130
|
+
})
|
|
131
|
+
child.on("close", (code) => {
|
|
132
|
+
if (code === 0) {
|
|
133
|
+
writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
|
|
122
137
|
return { action: "upgraded", localVersion, remoteVersion }
|
|
123
138
|
} catch (err) {
|
|
124
139
|
const msg = err instanceof Error ? err.message : String(err)
|
|
@@ -126,6 +141,16 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
126
141
|
}
|
|
127
142
|
}
|
|
128
143
|
|
|
144
|
+
function readXpGateConfig(): { autoUpgrade?: boolean } | null {
|
|
145
|
+
const cfgPath = join(homedir(), ".xp-gate", "config.json")
|
|
146
|
+
try {
|
|
147
|
+
if (!existsSync(cfgPath)) return null
|
|
148
|
+
return JSON.parse(readFileSync(cfgPath, "utf8"))
|
|
149
|
+
} catch {
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
129
154
|
// ── OpenCode plugin version check (notification only) ──
|
|
130
155
|
|
|
131
156
|
async function checkPluginUpdate(pluginDir: string): Promise<void> {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { existsSync, readFileSync } from "node:fs"
|
|
16
16
|
import { join } from "node:path"
|
|
17
17
|
import type { TuiPlugin, TuiSlotPlugin, TuiSlotProps } from "@opencode-ai/plugin/tui"
|
|
18
|
+
import { PHASE_NAMES, PHASE_ORDER, getLatestTimestamp, isStale } from "../../src/npm-package/lib/shared-phase-constants.js"
|
|
18
19
|
|
|
19
20
|
// ── Sprint state schema ──
|
|
20
21
|
|
|
@@ -44,24 +45,6 @@ interface SprintState {
|
|
|
44
45
|
phase_history?: SprintPhaseHistory[]
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
// ── Constants ──
|
|
48
|
-
|
|
49
|
-
const PHASE_NAMES: Record<string, string> = {
|
|
50
|
-
"-1": "ISOLATE",
|
|
51
|
-
"-0.5": "AUTO-ESTIMATE",
|
|
52
|
-
"0": "THINK",
|
|
53
|
-
"1": "PLAN",
|
|
54
|
-
"2": "BUILD",
|
|
55
|
-
"3": "REVIEW",
|
|
56
|
-
"4": "USER ACCEPT",
|
|
57
|
-
"5": "FEEDBACK",
|
|
58
|
-
"6": "SHIP",
|
|
59
|
-
"7": "LAND",
|
|
60
|
-
"8": "CLEANUP",
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const PHASE_ORDER = ["-1", "-0.5", "0", "1", "2", "3", "4", "5", "6", "7", "8"]
|
|
64
|
-
|
|
65
48
|
// ── Helpers ──
|
|
66
49
|
|
|
67
50
|
function readSprintState(dir: string): SprintState | null {
|
|
@@ -74,26 +57,6 @@ function readSprintState(dir: string): SprintState | null {
|
|
|
74
57
|
}
|
|
75
58
|
}
|
|
76
59
|
|
|
77
|
-
function isStale(state: SprintState): boolean {
|
|
78
|
-
if (!state || !state.started_at) return false
|
|
79
|
-
const started = new Date(state.started_at).getTime()
|
|
80
|
-
if (isNaN(started)) return false
|
|
81
|
-
let latest = started
|
|
82
|
-
if (Array.isArray(state.phase_history)) {
|
|
83
|
-
for (const ph of state.phase_history) {
|
|
84
|
-
if (ph.completed_at) {
|
|
85
|
-
const t = new Date(ph.completed_at).getTime()
|
|
86
|
-
if (!isNaN(t) && t > latest) latest = t
|
|
87
|
-
}
|
|
88
|
-
if (ph.started_at) {
|
|
89
|
-
const t = new Date(ph.started_at).getTime()
|
|
90
|
-
if (!isNaN(t) && t > latest) latest = t
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return Date.now() - latest > 3_600_000
|
|
95
|
-
}
|
|
96
|
-
|
|
97
60
|
function statusSymbol(status: string | undefined, key: string, currentPhase: string | number | undefined): string {
|
|
98
61
|
if (status === "completed") return "✓"
|
|
99
62
|
if (status === "in_progress") return "→"
|
|
@@ -109,57 +72,63 @@ function renderPhaseLine(key: string, history: SprintPhaseHistory | undefined, c
|
|
|
109
72
|
.replace(/\s+$/, "")
|
|
110
73
|
}
|
|
111
74
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const lines: string[] = []
|
|
116
|
-
const metrics = state.metrics || {}
|
|
117
|
-
const currentPhase = state.phase
|
|
118
|
-
|
|
119
|
-
// Build lookup
|
|
120
|
-
const historyByPhase: Record<string, SprintPhaseHistory> = {}
|
|
75
|
+
function buildPhaseLookup(state: SprintState): Record<string, SprintPhaseHistory> {
|
|
76
|
+
const lookup: Record<string, SprintPhaseHistory> = {}
|
|
121
77
|
if (Array.isArray(state.phase_history)) {
|
|
122
78
|
for (const ph of state.phase_history) {
|
|
123
|
-
|
|
79
|
+
lookup[String(ph.phase)] = ph
|
|
124
80
|
}
|
|
125
81
|
}
|
|
82
|
+
return lookup
|
|
83
|
+
}
|
|
126
84
|
|
|
127
|
-
|
|
128
|
-
|
|
85
|
+
function buildMetricsLine(metrics: SprintState["metrics"]): string | null {
|
|
86
|
+
const parts: string[] = []
|
|
87
|
+
if (metrics?.tests_passed != null) parts.push(`tests:${metrics.tests_passed}`)
|
|
88
|
+
if (metrics?.coverage_pct != null) parts.push(`cov:${metrics.coverage_pct}%`)
|
|
89
|
+
return parts.length > 0 ? parts.join(" ") : null
|
|
90
|
+
}
|
|
129
91
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
if (metrics.coverage_pct != null) {
|
|
136
|
-
metricParts.push(`cov:${metrics.coverage_pct}%`)
|
|
137
|
-
}
|
|
138
|
-
if (metricParts.length > 0) {
|
|
139
|
-
lines.push(metricParts.join(" "))
|
|
140
|
-
}
|
|
92
|
+
function buildStaleWarning(state: SprintState): string | null {
|
|
93
|
+
if (!state || !state.started_at) return null
|
|
94
|
+
return isStale(state) ? "⚠ idle >1h" : null
|
|
95
|
+
}
|
|
141
96
|
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
97
|
+
function renderBuildReqs(history: SprintPhaseHistory): string[] {
|
|
98
|
+
if (!history.reqs) return []
|
|
99
|
+
return Object.entries(history.reqs)
|
|
100
|
+
.filter(([, r]) => r.name)
|
|
101
|
+
.map(([id, r]) => ` ${statusSymbol(r.status, id, undefined)} ${r.name}`)
|
|
102
|
+
}
|
|
146
103
|
|
|
147
|
-
|
|
104
|
+
function renderPhaseLines(
|
|
105
|
+
historyByPhase: Record<string, SprintPhaseHistory>,
|
|
106
|
+
currentPhase: string | number | undefined,
|
|
107
|
+
): string[] {
|
|
108
|
+
const lines: string[] = []
|
|
148
109
|
for (const key of PHASE_ORDER) {
|
|
149
110
|
const history = historyByPhase[key]
|
|
150
|
-
// Only show phases with activity or current
|
|
151
111
|
if (!history && String(currentPhase) !== key) continue
|
|
152
|
-
|
|
153
|
-
lines.push(line)
|
|
154
|
-
|
|
155
|
-
// REQ-level progress for BUILD phase
|
|
112
|
+
lines.push(renderPhaseLine(key, history, currentPhase))
|
|
156
113
|
if (key === "2" && history?.reqs) {
|
|
157
|
-
|
|
158
|
-
.filter(([, r]) => r.name)
|
|
159
|
-
.map(([id, r]) => ` ${statusSymbol(r.status, id, undefined)} ${r.name}`)
|
|
160
|
-
if (reqNames.length > 0) lines.push(...reqNames)
|
|
114
|
+
lines.push(...renderBuildReqs(history))
|
|
161
115
|
}
|
|
162
116
|
}
|
|
117
|
+
return lines
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function renderSprintSidebar(state: SprintState): string {
|
|
121
|
+
if (!state || !state.task_description) return ""
|
|
122
|
+
|
|
123
|
+
const lines: string[] = [`SPRINT: ${state.task_description}`]
|
|
124
|
+
const metricsLine = buildMetricsLine(state.metrics)
|
|
125
|
+
if (metricsLine) lines.push(metricsLine)
|
|
126
|
+
|
|
127
|
+
const staleWarning = buildStaleWarning(state)
|
|
128
|
+
if (staleWarning) lines.push(staleWarning)
|
|
129
|
+
|
|
130
|
+
const historyByPhase = buildPhaseLookup(state)
|
|
131
|
+
lines.push(...renderPhaseLines(historyByPhase, state.phase))
|
|
163
132
|
|
|
164
133
|
return lines.join("\n")
|
|
165
134
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.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-19
|
|
4
|
+
**Commit:** b67f7f9
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.9.
|
|
6
|
+
**Version:** 0.9.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|