@boyingliu01/xp-gate 0.10.12 → 0.10.14
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__/doctor.test.js +155 -0
- package/lib/doctor.js +126 -0
- package/lib/init.js +12 -0
- 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__/tui-plugin.test.ts +121 -1
- package/plugins/opencode/index.ts +2 -0
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/scripts/prepack.cjs +15 -0
- 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 +24 -7
- 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
|
@@ -102,6 +102,15 @@ describe('doctor', () => {
|
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
function tuiJsonPath() {
|
|
106
|
+
return path.join(tmpHome, '.config', 'opencode', 'tui.json');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function ensureTuiRegistered() {
|
|
110
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
111
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ plugin: ['@boyingliu01/opencode-plugin/tui'] }, null, 2));
|
|
112
|
+
}
|
|
113
|
+
|
|
105
114
|
function setupLocalInstall() {
|
|
106
115
|
createXpGatePreCommit(projectHooksDir());
|
|
107
116
|
createXpGatePrePush(projectHooksDir());
|
|
@@ -183,6 +192,7 @@ describe('doctor', () => {
|
|
|
183
192
|
|
|
184
193
|
it('AC-05: doctor reports all checks passed for healthy local install', async () => {
|
|
185
194
|
setupLocalInstall();
|
|
195
|
+
ensureTuiRegistered();
|
|
186
196
|
seedVersionCache();
|
|
187
197
|
mockExecSuccess();
|
|
188
198
|
const { doctor } = require('../doctor');
|
|
@@ -198,6 +208,7 @@ describe('doctor', () => {
|
|
|
198
208
|
|
|
199
209
|
it('AC-05: doctor reports all checks passed for healthy global install', async () => {
|
|
200
210
|
setupGlobalInstall();
|
|
211
|
+
ensureTuiRegistered();
|
|
201
212
|
seedVersionCache();
|
|
202
213
|
mockExecSuccess();
|
|
203
214
|
const { doctor } = require('../doctor');
|
|
@@ -352,6 +363,7 @@ describe('doctor', () => {
|
|
|
352
363
|
|
|
353
364
|
it('AC-10: doctor --fix corrects core.hooksPath in global mode', async () => {
|
|
354
365
|
setupGlobalInstall();
|
|
366
|
+
ensureTuiRegistered();
|
|
355
367
|
seedVersionCache();
|
|
356
368
|
// Mock hooksPath pointing somewhere else
|
|
357
369
|
execSpy = vi.spyOn(childProcess, 'execSync').mockImplementation((cmd) => {
|
|
@@ -455,6 +467,7 @@ describe('doctor', () => {
|
|
|
455
467
|
|
|
456
468
|
it('passes version check when config version matches package version', async () => {
|
|
457
469
|
setupLocalInstall();
|
|
470
|
+
ensureTuiRegistered();
|
|
458
471
|
seedVersionCache();
|
|
459
472
|
// Write config with matching version
|
|
460
473
|
const pkg = JSON.parse(fs.readFileSync(
|
|
@@ -476,6 +489,7 @@ describe('doctor', () => {
|
|
|
476
489
|
|
|
477
490
|
it('passes version check when config has no version field (legacy)', async () => {
|
|
478
491
|
setupLocalInstall();
|
|
492
|
+
ensureTuiRegistered();
|
|
479
493
|
seedVersionCache();
|
|
480
494
|
// Config without version field — legacy install, should not fail
|
|
481
495
|
mockExecSuccess();
|
|
@@ -521,6 +535,7 @@ describe('doctor', () => {
|
|
|
521
535
|
|
|
522
536
|
it('passes templateDir check when templateDir matches current platform', async () => {
|
|
523
537
|
setupLocalInstall();
|
|
538
|
+
ensureTuiRegistered();
|
|
524
539
|
seedVersionCache();
|
|
525
540
|
// Write config with correct qoder templateDir
|
|
526
541
|
const cfg = JSON.parse(fs.readFileSync(configFile(), 'utf8'));
|
|
@@ -546,6 +561,7 @@ describe('doctor', () => {
|
|
|
546
561
|
|
|
547
562
|
it('passes templateDir check when config has no templateDir field (legacy)', async () => {
|
|
548
563
|
setupLocalInstall();
|
|
564
|
+
ensureTuiRegistered();
|
|
549
565
|
seedVersionCache();
|
|
550
566
|
// Config without templateDir — legacy install, should not fail
|
|
551
567
|
mockExecSuccess();
|
|
@@ -563,6 +579,7 @@ describe('doctor', () => {
|
|
|
563
579
|
|
|
564
580
|
it('AC-004-01: doctor shows upgrade prompt at end when outdated', async () => {
|
|
565
581
|
setupLocalInstall();
|
|
582
|
+
ensureTuiRegistered();
|
|
566
583
|
mockExecSuccess();
|
|
567
584
|
// Remove version cache so checkUpgrade hits the real npm registry
|
|
568
585
|
const cachePath = path.join(tmpHome, '.xp-gate', 'version-cache.json');
|
|
@@ -582,6 +599,7 @@ describe('doctor', () => {
|
|
|
582
599
|
|
|
583
600
|
it('AC-004-02: doctor does NOT show upgrade prompt when up to date', async () => {
|
|
584
601
|
setupLocalInstall();
|
|
602
|
+
ensureTuiRegistered();
|
|
585
603
|
mockExecSuccess();
|
|
586
604
|
// Write a cache with a future version so checkUpgrade says "not outdated"
|
|
587
605
|
const cachePath = path.join(tmpHome, '.xp-gate', 'version-cache.json');
|
|
@@ -606,6 +624,7 @@ describe('doctor', () => {
|
|
|
606
624
|
|
|
607
625
|
it('AC-004-03: doctor does NOT fail when version check throws', async () => {
|
|
608
626
|
setupLocalInstall();
|
|
627
|
+
ensureTuiRegistered();
|
|
609
628
|
seedVersionCache();
|
|
610
629
|
mockExecSuccess();
|
|
611
630
|
// Write corrupt cache to trigger checkUpgrade error path
|
|
@@ -642,4 +661,140 @@ describe('doctor', () => {
|
|
|
642
661
|
expect.stringContaining('Restored')
|
|
643
662
|
);
|
|
644
663
|
});
|
|
664
|
+
|
|
665
|
+
// === Check 9: TUI auto-registration (tui.json) ===
|
|
666
|
+
|
|
667
|
+
it('Check 9: PASS when tui.json has @boyingliu01/opencode-plugin/tui registered', async () => {
|
|
668
|
+
setupLocalInstall();
|
|
669
|
+
seedVersionCache();
|
|
670
|
+
mockExecSuccess();
|
|
671
|
+
// Create tui.json with the plugin registered
|
|
672
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
673
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ plugin: ['@boyingliu01/opencode-plugin/tui'] }, null, 2));
|
|
674
|
+
const { doctor } = require('../doctor');
|
|
675
|
+
|
|
676
|
+
const result = await doctor([]);
|
|
677
|
+
|
|
678
|
+
expect(result).toBe(0);
|
|
679
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
680
|
+
expect.stringContaining('@boyingliu01/opencode-plugin/tui registered')
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it('Check 9: FAIL when tui.json is missing', async () => {
|
|
685
|
+
setupLocalInstall();
|
|
686
|
+
seedVersionCache();
|
|
687
|
+
mockExecSuccess();
|
|
688
|
+
// Ensure no tui.json
|
|
689
|
+
if (fs.existsSync(tuiJsonPath())) fs.unlinkSync(tuiJsonPath());
|
|
690
|
+
const { doctor } = require('../doctor');
|
|
691
|
+
|
|
692
|
+
const result = await doctor([]);
|
|
693
|
+
|
|
694
|
+
expect(result).toBe(1);
|
|
695
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
696
|
+
expect.stringContaining('TUI registration: Not registered')
|
|
697
|
+
);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
it('Check 9: FAIL when tui.json exists without @boyingliu01/opencode-plugin/tui entry', async () => {
|
|
701
|
+
setupLocalInstall();
|
|
702
|
+
seedVersionCache();
|
|
703
|
+
mockExecSuccess();
|
|
704
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
705
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ plugin: ['some-other-plugin'] }, null, 2));
|
|
706
|
+
const { doctor } = require('../doctor');
|
|
707
|
+
|
|
708
|
+
const result = await doctor([]);
|
|
709
|
+
|
|
710
|
+
expect(result).toBe(1);
|
|
711
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
712
|
+
expect.stringContaining('TUI registration: Not registered')
|
|
713
|
+
);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it('Check 9: WARN when tui.json exists but has no plugin array', async () => {
|
|
717
|
+
setupLocalInstall();
|
|
718
|
+
seedVersionCache();
|
|
719
|
+
mockExecSuccess();
|
|
720
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
721
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ someKey: 'value' }, null, 2));
|
|
722
|
+
const { doctor } = require('../doctor');
|
|
723
|
+
|
|
724
|
+
const result = await doctor([]);
|
|
725
|
+
|
|
726
|
+
expect(result).toBe(1);
|
|
727
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
728
|
+
expect.stringContaining('TUI registration: Not registered')
|
|
729
|
+
);
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
it('Check 9: FAIL with backup when tui.json is corrupt JSON', async () => {
|
|
733
|
+
setupLocalInstall();
|
|
734
|
+
seedVersionCache();
|
|
735
|
+
mockExecSuccess();
|
|
736
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
737
|
+
fs.writeFileSync(tuiJsonPath(), 'this is not { valid json');
|
|
738
|
+
const { doctor } = require('../doctor');
|
|
739
|
+
|
|
740
|
+
const result = await doctor([]);
|
|
741
|
+
|
|
742
|
+
expect(result).toBe(1);
|
|
743
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
744
|
+
expect.stringContaining('TUI registration: Corrupt')
|
|
745
|
+
);
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// === --fix TUI registration ===
|
|
749
|
+
|
|
750
|
+
it('--fix: diagnoses TUI not registered then re-diagnoses after fix', async () => {
|
|
751
|
+
setupLocalInstall();
|
|
752
|
+
seedVersionCache();
|
|
753
|
+
mockExecSuccess();
|
|
754
|
+
// No tui.json
|
|
755
|
+
if (fs.existsSync(path.join(tmpHome, '.config', 'opencode'))) {
|
|
756
|
+
fs.rmSync(path.join(tmpHome, '.config', 'opencode'), { recursive: true, force: true });
|
|
757
|
+
}
|
|
758
|
+
const { doctor } = require('../doctor');
|
|
759
|
+
|
|
760
|
+
const result = await doctor(['--fix']);
|
|
761
|
+
|
|
762
|
+
expect(result).toBe(0);
|
|
763
|
+
// After fix, tui.json should exist with the plugin registered
|
|
764
|
+
expect(fs.existsSync(tuiJsonPath())).toBe(true);
|
|
765
|
+
const tui = JSON.parse(fs.readFileSync(tuiJsonPath(), 'utf8'));
|
|
766
|
+
expect(tui.plugin).toContain('@boyingliu01/opencode-plugin/tui');
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
it('--fix: append to existing tui.json plugin array', async () => {
|
|
770
|
+
setupLocalInstall();
|
|
771
|
+
seedVersionCache();
|
|
772
|
+
mockExecSuccess();
|
|
773
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
774
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ plugin: ['some-other-plugin'] }, null, 2));
|
|
775
|
+
const { doctor } = require('../doctor');
|
|
776
|
+
|
|
777
|
+
const result = await doctor(['--fix']);
|
|
778
|
+
|
|
779
|
+
expect(result).toBe(0);
|
|
780
|
+
const tui = JSON.parse(fs.readFileSync(tuiJsonPath(), 'utf8'));
|
|
781
|
+
expect(tui.plugin).toContain('some-other-plugin');
|
|
782
|
+
expect(tui.plugin).toContain('@boyingliu01/opencode-plugin/tui');
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it('--fix: idempotent — does not duplicate entry when already registered', async () => {
|
|
786
|
+
setupLocalInstall();
|
|
787
|
+
seedVersionCache();
|
|
788
|
+
mockExecSuccess();
|
|
789
|
+
fs.mkdirSync(path.dirname(tuiJsonPath()), { recursive: true });
|
|
790
|
+
fs.writeFileSync(tuiJsonPath(), JSON.stringify({ plugin: ['@boyingliu01/opencode-plugin/tui'] }, null, 2));
|
|
791
|
+
const { doctor } = require('../doctor');
|
|
792
|
+
|
|
793
|
+
const result = await doctor(['--fix']);
|
|
794
|
+
|
|
795
|
+
expect(result).toBe(0);
|
|
796
|
+
const tui = JSON.parse(fs.readFileSync(tuiJsonPath(), 'utf8'));
|
|
797
|
+
// Should still have exactly one entry
|
|
798
|
+
expect(tui.plugin.filter(p => p === '@boyingliu01/opencode-plugin/tui').length).toBe(1);
|
|
799
|
+
});
|
|
645
800
|
});
|
package/lib/doctor.js
CHANGED
|
@@ -229,6 +229,9 @@ function diagnose() {
|
|
|
229
229
|
// --- Check 6: Environment dependencies ---
|
|
230
230
|
checkEnv(checks);
|
|
231
231
|
|
|
232
|
+
// --- Check 7: TUI auto-registration ---
|
|
233
|
+
issues += diagnoseTuiRegistration(checks);
|
|
234
|
+
|
|
232
235
|
return { checks, issues };
|
|
233
236
|
}
|
|
234
237
|
|
|
@@ -438,6 +441,7 @@ function fixIssues(checks, config) {
|
|
|
438
441
|
fixed = fixHooksByMode(config, srcDir) || fixed;
|
|
439
442
|
fixed = fixGlobalHooksPath(config) || fixed;
|
|
440
443
|
fixed = fixMissingAdapters(config.mode, srcDir, getAdaptersDirByMode(config)) || fixed;
|
|
444
|
+
fixed = fixTuiRegistration() || fixed;
|
|
441
445
|
|
|
442
446
|
if (!fixed) {
|
|
443
447
|
console.log(' No fixable issues found.');
|
|
@@ -499,6 +503,124 @@ function diagnoseOpenCodePlugin(checks) {
|
|
|
499
503
|
return 0;
|
|
500
504
|
}
|
|
501
505
|
|
|
506
|
+
/**
|
|
507
|
+
* TUI registration path and expected plugin entry.
|
|
508
|
+
*/
|
|
509
|
+
const TUI_JSON_PATH = path.join(HOME_DIR, '.config', 'opencode', 'tui.json');
|
|
510
|
+
const TUI_PLUGIN_ENTRY = '@boyingliu01/opencode-plugin/tui';
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Read and parse tui.json, returning { data, error }.
|
|
514
|
+
* data = parsed object on success, null on file missing, undefined on corrupt.
|
|
515
|
+
*/
|
|
516
|
+
function readTuiJson() {
|
|
517
|
+
if (!fs.existsSync(TUI_JSON_PATH)) return { data: null, error: null };
|
|
518
|
+
try {
|
|
519
|
+
const raw = fs.readFileSync(TUI_JSON_PATH, 'utf8');
|
|
520
|
+
const data = JSON.parse(raw);
|
|
521
|
+
return { data, error: null };
|
|
522
|
+
} catch (e) {
|
|
523
|
+
return { data: undefined, error: `Corrupt JSON: ${e.message}` };
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Check 9: TUI auto-registration in ~/.config/opencode/tui.json.
|
|
529
|
+
* @returns {number} issue count
|
|
530
|
+
*/
|
|
531
|
+
function diagnoseTuiRegistration(checks) {
|
|
532
|
+
const { data, error } = readTuiJson();
|
|
533
|
+
|
|
534
|
+
if (error) {
|
|
535
|
+
checks.push({ name: 'TUI registration', status: 'FAIL', detail: error });
|
|
536
|
+
return 1;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (data === null) {
|
|
540
|
+
checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
|
|
541
|
+
return 1;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const plugins = Array.isArray(data.plugin) ? data.plugin : [];
|
|
545
|
+
if (plugins.includes(TUI_PLUGIN_ENTRY)) {
|
|
546
|
+
checks.push({ name: 'TUI registration', status: 'PASS', detail: `${TUI_PLUGIN_ENTRY} registered` });
|
|
547
|
+
return 0;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
checks.push({ name: 'TUI registration', status: 'FAIL', detail: 'Not registered' });
|
|
551
|
+
return 1;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Fix TUI registration: ensure @boyingliu01/opencode-plugin/tui is in tui.json.
|
|
556
|
+
* Uses atomic write (tmp + renameSync) for JSON safety.
|
|
557
|
+
* On corrupt JSON: backup to .corrupt-{timestamp}.bak then rebuild.
|
|
558
|
+
* Idempotent: skips if already registered.
|
|
559
|
+
* @returns {boolean} Whether a fix was applied
|
|
560
|
+
*/
|
|
561
|
+
function fixTuiRegistration() {
|
|
562
|
+
const { data, error } = readTuiJson();
|
|
563
|
+
|
|
564
|
+
// Corrupt JSON: backup old file, rebuild from scratch
|
|
565
|
+
if (error && data === undefined) {
|
|
566
|
+
const ts = Date.now();
|
|
567
|
+
const backupPath = `${TUI_JSON_PATH}.corrupt-${ts}.bak`;
|
|
568
|
+
try {
|
|
569
|
+
fs.copyFileSync(TUI_JSON_PATH, backupPath);
|
|
570
|
+
console.log(` ⚠ TUI config corrupted — backed up to ${backupPath}`);
|
|
571
|
+
} catch { /* non-critical */ }
|
|
572
|
+
// Rebuild fresh
|
|
573
|
+
const dir = path.dirname(TUI_JSON_PATH);
|
|
574
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
575
|
+
const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
|
|
576
|
+
const tmpPath = `${TUI_JSON_PATH}.tmp`;
|
|
577
|
+
fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
|
|
578
|
+
fs.renameSync(tmpPath, TUI_JSON_PATH);
|
|
579
|
+
console.log(` ✓ Registered ${TUI_PLUGIN_ENTRY} in TUI (rebuilt after corrupt backup)`);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// File doesn't exist: create it
|
|
584
|
+
if (data === null) {
|
|
585
|
+
const dir = path.dirname(TUI_JSON_PATH);
|
|
586
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
587
|
+
const newConfig = { plugin: [TUI_PLUGIN_ENTRY] };
|
|
588
|
+
const tmpPath = `${TUI_JSON_PATH}.tmp`;
|
|
589
|
+
fs.writeFileSync(tmpPath, JSON.stringify(newConfig, null, 2));
|
|
590
|
+
fs.renameSync(tmpPath, TUI_JSON_PATH);
|
|
591
|
+
console.log(` ✓ Created TUI config with ${TUI_PLUGIN_ENTRY}`);
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// File exists, check if plugin already registered (idempotent)
|
|
596
|
+
const plugins = Array.isArray(data.plugin) ? data.plugin : [];
|
|
597
|
+
if (plugins.includes(TUI_PLUGIN_ENTRY)) return false;
|
|
598
|
+
|
|
599
|
+
// Append plugin entry
|
|
600
|
+
data.plugin = plugins.concat([TUI_PLUGIN_ENTRY]);
|
|
601
|
+
const tmpPath = `${TUI_JSON_PATH}.tmp`;
|
|
602
|
+
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
603
|
+
fs.renameSync(tmpPath, TUI_JSON_PATH);
|
|
604
|
+
console.log(` ✓ Added ${TUI_PLUGIN_ENTRY} to TUI config`);
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Wrapper for init.js: ensure TUI is registered without console output.
|
|
610
|
+
* Returns true if the plugin is already registered or was just added.
|
|
611
|
+
*/
|
|
612
|
+
function ensureTuiRegistration() {
|
|
613
|
+
const { data } = readTuiJson();
|
|
614
|
+
if (data === null || data === undefined) {
|
|
615
|
+
fixTuiRegistration();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const plugins = Array.isArray(data.plugin) ? data.plugin : [];
|
|
619
|
+
if (!plugins.includes(TUI_PLUGIN_ENTRY)) {
|
|
620
|
+
fixTuiRegistration();
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
502
624
|
async function doctor(args) {
|
|
503
625
|
const fixMode = args.includes('--fix');
|
|
504
626
|
|
|
@@ -551,4 +673,8 @@ module.exports = {
|
|
|
551
673
|
fixMissingHooks,
|
|
552
674
|
fixCoreHooksPath,
|
|
553
675
|
fixMissingAdapters,
|
|
676
|
+
diagnoseTuiRegistration,
|
|
677
|
+
fixTuiRegistration,
|
|
678
|
+
ensureTuiRegistration,
|
|
679
|
+
readTuiJson,
|
|
554
680
|
};
|
package/lib/init.js
CHANGED
|
@@ -340,6 +340,12 @@ async function installLocal(args) {
|
|
|
340
340
|
injectKarpathyPrinciples(projectRoot);
|
|
341
341
|
configureOpenCodePlugin(srcDir, projectRoot);
|
|
342
342
|
|
|
343
|
+
// Auto-register TUI plugin globally (idempotent)
|
|
344
|
+
try {
|
|
345
|
+
const { ensureTuiRegistration } = require('../lib/doctor.js');
|
|
346
|
+
ensureTuiRegistration();
|
|
347
|
+
} catch { /* non-critical: TUI registration is best-effort */ }
|
|
348
|
+
|
|
343
349
|
console.log('\nInstallation complete!');
|
|
344
350
|
console.log('Run git commit to trigger quality gates');
|
|
345
351
|
return 0;
|
|
@@ -390,6 +396,12 @@ async function setupGlobal(args) {
|
|
|
390
396
|
const manifest = generateGlobalManifest(srcDir);
|
|
391
397
|
updateConfig({ lastInit: new Date().toISOString(), mode: 'global', templateDir: TEMPLATE_DIR, manifest });
|
|
392
398
|
|
|
399
|
+
// Auto-register TUI plugin globally (idempotent)
|
|
400
|
+
try {
|
|
401
|
+
const { ensureTuiRegistration } = require('../lib/doctor.js');
|
|
402
|
+
ensureTuiRegistration();
|
|
403
|
+
} catch { /* non-critical: TUI registration is best-effort */ }
|
|
404
|
+
|
|
393
405
|
console.log('\nGlobal setup complete!');
|
|
394
406
|
console.log('All git repositories will now use xp-gate quality gates.');
|
|
395
407
|
console.log('Per-project adapters can still override by creating <repo>/githooks/');
|
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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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.14",
|
|
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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -13,7 +13,6 @@ import { describe, it, before, after } from "node:test"
|
|
|
13
13
|
import assert from "node:assert/strict"
|
|
14
14
|
import { randomUUID } from "node:crypto"
|
|
15
15
|
import { mkdirSync, writeFileSync, rmSync } from "node:fs"
|
|
16
|
-
import { join } from "node:path"
|
|
17
16
|
import { tmpdir } from "node:os"
|
|
18
17
|
|
|
19
18
|
// Import the functions under test
|
|
@@ -421,3 +420,124 @@ void describe("multi-sprint rendering", () => {
|
|
|
421
420
|
assert.ok(output.includes("Minimal sprint"))
|
|
422
421
|
})
|
|
423
422
|
})
|
|
423
|
+
|
|
424
|
+
// ── Early-phase placeholder rendering ──
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Renders panel content with early-phase placeholder fallback.
|
|
428
|
+
* Mirrors the planned renderContent(dir, sprints, upgradeNotice) from tui-plugin.ts.
|
|
429
|
+
* Expected to be the actual implementation after TDD cycle.
|
|
430
|
+
*/
|
|
431
|
+
import { existsSync } from "node:fs"
|
|
432
|
+
import { dirname, resolve, parse, join } from "node:path"
|
|
433
|
+
|
|
434
|
+
function findGitRoot(startDir: string): string | null {
|
|
435
|
+
let current = resolve(startDir);
|
|
436
|
+
const root = parse(current).root;
|
|
437
|
+
const seen = new Set<string>();
|
|
438
|
+
while (current !== root) {
|
|
439
|
+
if (seen.has(current)) break;
|
|
440
|
+
seen.add(current);
|
|
441
|
+
if (existsSync(join(current, '.git'))) return current;
|
|
442
|
+
const parent = dirname(current);
|
|
443
|
+
if (parent === current) break;
|
|
444
|
+
current = parent;
|
|
445
|
+
}
|
|
446
|
+
if (existsSync(join(root, '.git'))) return root;
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function renderContentWithPlaceholder(
|
|
451
|
+
dir: string,
|
|
452
|
+
sprints: { state: Record<string, unknown>; sourcePath: string; worktreeExists: boolean }[],
|
|
453
|
+
upgradeNotice: string | null,
|
|
454
|
+
): string | null {
|
|
455
|
+
if (sprints.length > 0) {
|
|
456
|
+
return upgradeNotice || null
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const hasStateDir = existsSync(join(dir, ".sprint-state"))
|
|
460
|
+
const gitRoot = findGitRoot(dir)
|
|
461
|
+
const hasWorktreesRoot = gitRoot ? existsSync(join(gitRoot, ".worktrees")) : false
|
|
462
|
+
|
|
463
|
+
if (hasStateDir) {
|
|
464
|
+
const placeholder = "SPRINT FLOW\n → 初始化中..."
|
|
465
|
+
return [upgradeNotice, placeholder].filter(Boolean).join("\n---\n")
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (hasWorktreesRoot) {
|
|
469
|
+
const placeholder = "SPRINT FLOW\n · 准备中..."
|
|
470
|
+
return [upgradeNotice, placeholder].filter(Boolean).join("\n---\n")
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return upgradeNotice || null
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
void describe("early-phase placeholder rendering", () => {
|
|
477
|
+
const tmpDir = join(tmpdir(), "xp-gate-tui-placeholder-" + randomUUID())
|
|
478
|
+
|
|
479
|
+
before(() => {
|
|
480
|
+
mkdirSync(tmpDir, { recursive: true })
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
after(() => {
|
|
484
|
+
rmSync(tmpDir, { recursive: true, force: true })
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
void it("returns null when no sprints and no .sprint-state/ directory and no .worktrees/", () => {
|
|
488
|
+
const result = renderContentWithPlaceholder(tmpDir, [], null)
|
|
489
|
+
assert.equal(result, null, "Should return null when nothing exists")
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
void it("returns '初始化中...' placeholder when .sprint-state/ directory exists but no sprint data", () => {
|
|
493
|
+
mkdirSync(join(tmpDir, ".sprint-state"), { recursive: true })
|
|
494
|
+
const result = renderContentWithPlaceholder(tmpDir, [], null)
|
|
495
|
+
assert.ok(result !== null, "Should return a placeholder string")
|
|
496
|
+
assert.ok(result!.includes("SPRINT FLOW"), "Should include SPRINT FLOW header")
|
|
497
|
+
assert.ok(result!.includes("初始化中"), "Should include 初始化中...")
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
void it("returns '准备中...' placeholder when .worktrees/ directory exists but no sprint data", () => {
|
|
501
|
+
// Must create .git/ dir for findGitRoot() to succeed
|
|
502
|
+
// Note: test 2 (above) may have created .sprint-state/ — clean it first
|
|
503
|
+
rmSync(join(tmpDir, ".sprint-state"), { recursive: true, force: true })
|
|
504
|
+
mkdirSync(join(tmpDir, ".git"), { recursive: true })
|
|
505
|
+
mkdirSync(join(tmpDir, ".worktrees"), { recursive: true })
|
|
506
|
+
|
|
507
|
+
const result = renderContentWithPlaceholder(tmpDir, [], null)
|
|
508
|
+
assert.ok(result !== null, "Should return a placeholder string")
|
|
509
|
+
assert.ok(result!.includes("SPRINT FLOW"), "Should include SPRINT FLOW header")
|
|
510
|
+
assert.ok(result!.includes("准备中"), "Should include 准备中...")
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
void it("prefers .sprint-state/ placeholder over .worktrees/ when both exist", () => {
|
|
514
|
+
mkdirSync(join(tmpDir, ".sprint-state"), { recursive: true })
|
|
515
|
+
const result = renderContentWithPlaceholder(tmpDir, [], null)
|
|
516
|
+
assert.ok(result!.includes("初始化中"), "Should prefer 初始化中 when .sprint-state/ exists")
|
|
517
|
+
assert.ok(!result!.includes("准备中"), "Should NOT show 准备中 when .sprint-state/ exists")
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
void it("includes upgrade notice banner above placeholder when both present", () => {
|
|
521
|
+
const notice = "✓ Auto-upgraded from v0.10.12 to v0.10.13"
|
|
522
|
+
const result = renderContentWithPlaceholder(tmpDir, [], notice)
|
|
523
|
+
assert.ok(result !== null)
|
|
524
|
+
assert.ok(result!.includes("Auto-upgraded"), "Should include upgrade notice")
|
|
525
|
+
assert.ok(result!.includes("SPRINT FLOW"), "Should include placeholder below notice")
|
|
526
|
+
// Upgrade notice should appear before SPRINT FLOW
|
|
527
|
+
const noticePos = result!.indexOf("Auto-upgraded")
|
|
528
|
+
const sprintPos = result!.indexOf("SPRINT FLOW")
|
|
529
|
+
assert.ok(noticePos < sprintPos, "Upgrade notice should come before SPRINT FLOW")
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
void it("shows upgrade notice only when no sprints and no placeholder dirs", () => {
|
|
533
|
+
// Reset — remove .sprint-state/ and .worktrees/
|
|
534
|
+
rmSync(join(tmpDir, ".sprint-state"), { recursive: true, force: true })
|
|
535
|
+
rmSync(join(tmpDir, ".worktrees"), { recursive: true, force: true })
|
|
536
|
+
|
|
537
|
+
const notice = "↑ New version v1.0.0 available"
|
|
538
|
+
const result = renderContentWithPlaceholder(tmpDir, [], notice)
|
|
539
|
+
assert.ok(result !== null, "Should return upgrade notice even without sprint dirs")
|
|
540
|
+
assert.ok(result!.includes("New version"), "Should include upgrade notice text")
|
|
541
|
+
assert.ok(!result!.includes("SPRINT FLOW"), "Should NOT show placeholder when nothing exists")
|
|
542
|
+
})
|
|
543
|
+
})
|
|
@@ -322,6 +322,8 @@ export const XpGatePlugin = async (input: OpenCodePluginInput) => {
|
|
|
322
322
|
if (!checked) {
|
|
323
323
|
checked = true
|
|
324
324
|
const msg = await runBackgroundUpdates(directory).catch(() => null)
|
|
325
|
+
// Primary notification: upgrade-notice.json → TUI sidebar banner
|
|
326
|
+
// Fallback: stderr for users without TUI panel registered
|
|
325
327
|
if (msg) process.stderr.write(`${msg}\n`)
|
|
326
328
|
}
|
|
327
329
|
},
|
|
@@ -80,6 +80,21 @@ function main() {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
console.error(`[prepack] done: ${copied} skills bundled for @boyingliu01/opencode-plugin`);
|
|
83
|
+
|
|
84
|
+
// Validate tui-plugin.ts structural integrity (Issue #248: stale cache detection)
|
|
85
|
+
const tuiFile = path.join(PLUGIN_ROOT, 'tui-plugin.ts');
|
|
86
|
+
const tuiContent = fs.readFileSync(tuiFile, 'utf8');
|
|
87
|
+
const ok1 = tuiContent.includes('discoverActiveSprints') && tuiContent.includes('.worktrees');
|
|
88
|
+
const ok2 = !tuiContent.match(/from\s+["'][^"']*\.\.\/\.\.\/src[^"']*["']/);
|
|
89
|
+
if (!ok1) {
|
|
90
|
+
console.error('[prepack] ERROR: tui-plugin.ts is missing discoverActiveSprints — old version detected');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
if (!ok2) {
|
|
94
|
+
console.error('[prepack] ERROR: tui-plugin.ts contains broken import paths to ../../src/...');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
console.error('[prepack] OK: tui-plugin.ts structural checks passed');
|
|
83
98
|
}
|
|
84
99
|
|
|
85
100
|
main();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-06-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-06-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -329,11 +329,29 @@ function renderMultiSprintSidebar(sprints: DiscoveredSprint[]): string | null {
|
|
|
329
329
|
return blocks.join("\n---\n");
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
function renderContent(sprints: DiscoveredSprint[], upgradeNotice: string | null): string | null {
|
|
332
|
+
function renderContent(sprints: DiscoveredSprint[], upgradeNotice: string | null, dir: string): string | null {
|
|
333
333
|
const sprintContent = renderMultiSprintSidebar(sprints)
|
|
334
|
-
|
|
335
|
-
if (
|
|
336
|
-
|
|
334
|
+
|
|
335
|
+
if (sprintContent) {
|
|
336
|
+
return [upgradeNotice, sprintContent].filter(Boolean).join("\n---\n")
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Early-phase placeholders: when no sprint data yet, check for directory hints
|
|
340
|
+
const hasStateDir = existsSync(join(dir, ".sprint-state"))
|
|
341
|
+
const gitRoot = findGitRoot(dir)
|
|
342
|
+
const hasWorktreesRoot = gitRoot ? existsSync(join(gitRoot, ".worktrees")) : false
|
|
343
|
+
|
|
344
|
+
if (hasStateDir) {
|
|
345
|
+
const placeholder = "SPRINT FLOW\n → 初始化中..."
|
|
346
|
+
return [upgradeNotice, placeholder].filter(Boolean).join("\n---\n")
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (hasWorktreesRoot) {
|
|
350
|
+
const placeholder = "SPRINT FLOW\n · 准备中..."
|
|
351
|
+
return [upgradeNotice, placeholder].filter(Boolean).join("\n---\n")
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return upgradeNotice || null
|
|
337
355
|
}
|
|
338
356
|
|
|
339
357
|
// ── Upgrade notice ──
|
|
@@ -376,15 +394,14 @@ const tuiPlugin: TuiSlotPlugin = {
|
|
|
376
394
|
const dir = process.env.XP_GATE_PROJECT_DIR || process.cwd();
|
|
377
395
|
const now = Date.now();
|
|
378
396
|
|
|
379
|
-
// Use cache if still valid for current directory
|
|
380
397
|
if (_cache && _cache.dir === dir && now - _cache.ts < CACHE_TTL_MS) {
|
|
381
|
-
return renderContent(_cache.data, _cache.upgradeNotice);
|
|
398
|
+
return renderContent(_cache.data, _cache.upgradeNotice, dir);
|
|
382
399
|
}
|
|
383
400
|
|
|
384
401
|
const sprints = discoverActiveSprints(dir);
|
|
385
402
|
const upgradeNotice = renderUpgradeNotice()
|
|
386
403
|
_cache = { data: sprints, ts: now, dir, upgradeNotice };
|
|
387
|
-
return renderContent(sprints, upgradeNotice);
|
|
404
|
+
return renderContent(sprints, upgradeNotice, dir);
|
|
388
405
|
},
|
|
389
406
|
},
|
|
390
407
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.14",
|
|
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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.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-25
|
|
4
|
+
**Commit:** 1fe912a
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.14.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|