@tekyzinc/gsd-t 2.20.7 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +417 -398
- package/README.md +5 -2
- package/bin/gsd-t.js +114 -123
- package/commands/gsd-t-complete-milestone.md +13 -2
- package/commands/gsd-t-debug.md +13 -0
- package/commands/gsd-t-execute.md +17 -0
- package/commands/gsd-t-help.md +15 -0
- package/commands/gsd-t-integrate.md +13 -0
- package/commands/gsd-t-partition.md +13 -0
- package/commands/gsd-t-plan.md +13 -0
- package/commands/gsd-t-qa.md +169 -0
- package/commands/gsd-t-quick.md +13 -0
- package/commands/gsd-t-test-sync.md +13 -0
- package/commands/gsd-t-triage-and-merge.md +167 -0
- package/commands/gsd-t-verify.md +19 -1
- package/commands/gsd-t-wave.md +4 -0
- package/docs/GSD-T-README.md +2 -0
- package/docs/architecture.md +82 -0
- package/docs/infrastructure.md +72 -0
- package/docs/requirements.md +43 -0
- package/docs/workflows.md +67 -0
- package/examples/.gsd-t/domains/example-domain/scope.md +13 -15
- package/package.json +2 -2
- package/scripts/gsd-t-heartbeat.js +4 -1
- package/scripts/npm-update-check.js +27 -0
- package/templates/CLAUDE-global.md +433 -414
- package/templates/progress.md +40 -38
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ A methodology for reliable, parallelizable development using Claude Code with op
|
|
|
18
18
|
npx @tekyzinc/gsd-t install
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
This installs
|
|
21
|
+
This installs 39 GSD-T commands + 3 utility commands to `~/.claude/commands/` and the global CLAUDE.md to `~/.claude/CLAUDE.md`. Works on Windows, Mac, and Linux.
|
|
22
22
|
|
|
23
23
|
### Start Using It
|
|
24
24
|
|
|
@@ -129,6 +129,7 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
|
|
|
129
129
|
| `/user:gsd-t-impact` | Analyze downstream effects | In wave |
|
|
130
130
|
| `/user:gsd-t-execute` | Run tasks (solo or team) | In wave |
|
|
131
131
|
| `/user:gsd-t-test-sync` | Sync tests with code changes | In wave |
|
|
132
|
+
| `/user:gsd-t-qa` | QA agent — test generation, execution, gap reporting | Auto-spawned |
|
|
132
133
|
| `/user:gsd-t-integrate` | Wire domains together | In wave |
|
|
133
134
|
| `/user:gsd-t-verify` | Run quality gates | In wave |
|
|
134
135
|
| `/user:gsd-t-complete-milestone` | Archive + git tag | In wave |
|
|
@@ -145,6 +146,7 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
|
|
|
145
146
|
| `/user:gsd-t-log` | Sync progress Decision Log with recent git activity | Manual |
|
|
146
147
|
| `/user:gsd-t-version-update` | Update GSD-T to latest version | Manual |
|
|
147
148
|
| `/user:gsd-t-version-update-all` | Update GSD-T + all registered projects | Manual |
|
|
149
|
+
| `/user:gsd-t-triage-and-merge` | Auto-review, merge, and publish GitHub branches | Manual |
|
|
148
150
|
|
|
149
151
|
### Backlog Management
|
|
150
152
|
|
|
@@ -281,8 +283,9 @@ get-stuff-done-teams/
|
|
|
281
283
|
├── LICENSE
|
|
282
284
|
├── bin/
|
|
283
285
|
│ └── gsd-t.js # CLI installer
|
|
284
|
-
├── commands/ #
|
|
286
|
+
├── commands/ # 42 slash commands
|
|
285
287
|
│ ├── gsd-t-*.md # 38 GSD-T workflow commands
|
|
288
|
+
│ ├── gsd.md # GSD-T smart router
|
|
286
289
|
│ ├── branch.md # Git branch helper
|
|
287
290
|
│ ├── checkin.md # Auto-version + commit/push helper
|
|
288
291
|
│ └── Claude-md.md # Reload CLAUDE.md directives
|
package/bin/gsd-t.js
CHANGED
|
@@ -104,6 +104,10 @@ function ensureDir(dir) {
|
|
|
104
104
|
fs.mkdirSync(dir, { recursive: true });
|
|
105
105
|
return true;
|
|
106
106
|
}
|
|
107
|
+
if (isSymlink(dir)) {
|
|
108
|
+
warn(`Refusing to use symlinked directory: ${dir}`);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
107
111
|
return false;
|
|
108
112
|
}
|
|
109
113
|
|
|
@@ -133,7 +137,12 @@ function validateVersion(ver) {
|
|
|
133
137
|
|
|
134
138
|
function validateProjectPath(p) {
|
|
135
139
|
try {
|
|
136
|
-
|
|
140
|
+
if (!path.isAbsolute(p) || !fs.existsSync(p)) return false;
|
|
141
|
+
const stat = fs.statSync(p);
|
|
142
|
+
if (!stat.isDirectory()) return false;
|
|
143
|
+
// On Unix, verify directory is owned by current user (defense-in-depth)
|
|
144
|
+
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) return false;
|
|
145
|
+
return true;
|
|
137
146
|
} catch {
|
|
138
147
|
return false;
|
|
139
148
|
}
|
|
@@ -381,19 +390,7 @@ function configureHeartbeatHooks(scriptPath) {
|
|
|
381
390
|
|
|
382
391
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
383
392
|
|
|
384
|
-
function
|
|
385
|
-
const isUpdate = opts.update || false;
|
|
386
|
-
const verb = isUpdate ? "Updating" : "Installing";
|
|
387
|
-
|
|
388
|
-
heading(`${verb} GSD-T ${versionLink()}`);
|
|
389
|
-
log("");
|
|
390
|
-
|
|
391
|
-
// 1. Create ~/.claude/commands/ if needed
|
|
392
|
-
if (ensureDir(COMMANDS_DIR)) {
|
|
393
|
-
success("Created ~/.claude/commands/");
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 2. Copy all command files
|
|
393
|
+
function installCommands(isUpdate) {
|
|
397
394
|
heading("Slash Commands");
|
|
398
395
|
const commandFiles = getCommandFiles();
|
|
399
396
|
const gsdtCommands = getGsdtCommands();
|
|
@@ -406,7 +403,6 @@ function doInstall(opts = {}) {
|
|
|
406
403
|
const dest = path.join(COMMANDS_DIR, file);
|
|
407
404
|
|
|
408
405
|
if (isUpdate && fs.existsSync(dest)) {
|
|
409
|
-
// Compare content — only overwrite if changed
|
|
410
406
|
const srcContent = fs.readFileSync(src, "utf8");
|
|
411
407
|
const destContent = fs.readFileSync(dest, "utf8");
|
|
412
408
|
if (normalizeEol(srcContent) === normalizeEol(destContent)) {
|
|
@@ -423,8 +419,10 @@ function doInstall(opts = {}) {
|
|
|
423
419
|
info(`${skipped} commands unchanged`);
|
|
424
420
|
}
|
|
425
421
|
success(`${gsdtCommands.length} GSD-T commands + ${utilityCommands.length} utilities ${isUpdate ? "updated" : "installed"} → ~/.claude/commands/`);
|
|
422
|
+
return { gsdtCommands, utilityCommands };
|
|
423
|
+
}
|
|
426
424
|
|
|
427
|
-
|
|
425
|
+
function installGlobalClaudeMd(isUpdate) {
|
|
428
426
|
heading("Global CLAUDE.md");
|
|
429
427
|
const globalSrc = path.join(PKG_TEMPLATES, "CLAUDE-global.md");
|
|
430
428
|
|
|
@@ -433,12 +431,10 @@ function doInstall(opts = {}) {
|
|
|
433
431
|
|
|
434
432
|
if (existing.includes("GSD-T: Contract-Driven Development")) {
|
|
435
433
|
if (isUpdate) {
|
|
436
|
-
// Check if there are customizations (lines not in our template)
|
|
437
434
|
const template = fs.readFileSync(globalSrc, "utf8");
|
|
438
435
|
if (normalizeEol(existing) === normalizeEol(template)) {
|
|
439
436
|
copyFile(globalSrc, GLOBAL_CLAUDE_MD, "CLAUDE.md updated (no customizations detected)");
|
|
440
437
|
} else {
|
|
441
|
-
// Backup and replace, warn about customizations
|
|
442
438
|
const backupPath = GLOBAL_CLAUDE_MD + ".backup-" + Date.now();
|
|
443
439
|
if (isSymlink(backupPath)) {
|
|
444
440
|
warn("Skipping backup — target is a symlink");
|
|
@@ -454,7 +450,6 @@ function doInstall(opts = {}) {
|
|
|
454
450
|
info("Run 'gsd-t update' to overwrite with latest version");
|
|
455
451
|
}
|
|
456
452
|
} else {
|
|
457
|
-
// Existing CLAUDE.md without GSD-T — append
|
|
458
453
|
if (isSymlink(GLOBAL_CLAUDE_MD)) {
|
|
459
454
|
warn("Skipping CLAUDE.md append — target is a symlink");
|
|
460
455
|
} else {
|
|
@@ -468,15 +463,26 @@ function doInstall(opts = {}) {
|
|
|
468
463
|
} else {
|
|
469
464
|
copyFile(globalSrc, GLOBAL_CLAUDE_MD, "CLAUDE.md installed → ~/.claude/CLAUDE.md");
|
|
470
465
|
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function doInstall(opts = {}) {
|
|
469
|
+
const isUpdate = opts.update || false;
|
|
470
|
+
const verb = isUpdate ? "Updating" : "Installing";
|
|
471
|
+
|
|
472
|
+
heading(`${verb} GSD-T ${versionLink()}`);
|
|
473
|
+
log("");
|
|
474
|
+
|
|
475
|
+
if (ensureDir(COMMANDS_DIR)) {
|
|
476
|
+
success("Created ~/.claude/commands/");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const { gsdtCommands, utilityCommands } = installCommands(isUpdate);
|
|
480
|
+
installGlobalClaudeMd(isUpdate);
|
|
471
481
|
|
|
472
|
-
// 4. Install heartbeat script + hooks
|
|
473
482
|
heading("Heartbeat (Real-time Events)");
|
|
474
483
|
installHeartbeat();
|
|
475
|
-
|
|
476
|
-
// 5. Save version
|
|
477
484
|
saveInstalledVersion();
|
|
478
485
|
|
|
479
|
-
// 6. Summary
|
|
480
486
|
heading("Installation Complete!");
|
|
481
487
|
log("");
|
|
482
488
|
log(` Commands: ${gsdtCommands.length} GSD-T + ${utilityCommands.length} utility commands in ~/.claude/commands/`);
|
|
@@ -518,53 +524,35 @@ function doUpdate() {
|
|
|
518
524
|
doInstall({ update: true });
|
|
519
525
|
}
|
|
520
526
|
|
|
521
|
-
function
|
|
522
|
-
if (!projectName) {
|
|
523
|
-
// Use current directory name
|
|
524
|
-
projectName = path.basename(process.cwd());
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
if (!validateProjectName(projectName)) {
|
|
528
|
-
error(`Invalid project name: "${projectName}"`);
|
|
529
|
-
info("Project names must start with a letter or number and contain only letters, numbers, dots, hyphens, underscores, or spaces (max 101 chars)");
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
heading(`Initializing GSD-T project: ${projectName}`);
|
|
534
|
-
log("");
|
|
535
|
-
|
|
536
|
-
const projectDir = process.cwd();
|
|
537
|
-
const today = new Date().toISOString().split("T")[0];
|
|
538
|
-
|
|
539
|
-
// 1. Create project CLAUDE.md
|
|
527
|
+
function initClaudeMd(projectDir, projectName, today) {
|
|
540
528
|
const claudeMdPath = path.join(projectDir, "CLAUDE.md");
|
|
541
529
|
if (isSymlink(claudeMdPath)) {
|
|
542
530
|
warn("Skipping CLAUDE.md — target is a symlink");
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
}
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
const template = fs.readFileSync(path.join(PKG_TEMPLATES, "CLAUDE-project.md"), "utf8");
|
|
535
|
+
const content = applyTokens(template, projectName, today);
|
|
536
|
+
fs.writeFileSync(claudeMdPath, content, { flag: "wx" });
|
|
537
|
+
success("CLAUDE.md created");
|
|
538
|
+
} catch (e) {
|
|
539
|
+
if (e.code === "EEXIST") {
|
|
540
|
+
const content = fs.readFileSync(claudeMdPath, "utf8");
|
|
541
|
+
if (content.includes("GSD-T Workflow")) {
|
|
542
|
+
info("CLAUDE.md already contains GSD-T section — skipping");
|
|
543
|
+
} else {
|
|
544
|
+
warn("CLAUDE.md exists but doesn't reference GSD-T");
|
|
545
|
+
info("Run /user:gsd-t-init inside Claude Code to add GSD-T section");
|
|
546
|
+
}
|
|
547
|
+
} else { throw e; }
|
|
560
548
|
}
|
|
549
|
+
}
|
|
561
550
|
|
|
562
|
-
|
|
551
|
+
function initDocs(projectDir, projectName, today) {
|
|
563
552
|
const docsDir = path.join(projectDir, "docs");
|
|
564
553
|
ensureDir(docsDir);
|
|
565
554
|
|
|
566
555
|
const docTemplates = ["requirements.md", "architecture.md", "workflows.md", "infrastructure.md"];
|
|
567
|
-
|
|
568
556
|
for (const file of docTemplates) {
|
|
569
557
|
const destPath = path.join(docsDir, file);
|
|
570
558
|
if (isSymlink(destPath)) {
|
|
@@ -581,8 +569,9 @@ function doInit(projectName) {
|
|
|
581
569
|
else { throw e; }
|
|
582
570
|
}
|
|
583
571
|
}
|
|
572
|
+
}
|
|
584
573
|
|
|
585
|
-
|
|
574
|
+
function initGsdtDir(projectDir, projectName, today) {
|
|
586
575
|
const gsdtDir = path.join(projectDir, ".gsd-t");
|
|
587
576
|
const contractsDir = path.join(gsdtDir, "contracts");
|
|
588
577
|
const domainsDir = path.join(gsdtDir, "domains");
|
|
@@ -590,7 +579,6 @@ function doInit(projectName) {
|
|
|
590
579
|
ensureDir(contractsDir);
|
|
591
580
|
ensureDir(domainsDir);
|
|
592
581
|
|
|
593
|
-
// .gitkeep files so empty dirs are tracked
|
|
594
582
|
for (const dir of [contractsDir, domainsDir]) {
|
|
595
583
|
const gitkeep = path.join(dir, ".gitkeep");
|
|
596
584
|
if (isSymlink(gitkeep)) continue;
|
|
@@ -618,8 +606,7 @@ function doInit(projectName) {
|
|
|
618
606
|
}
|
|
619
607
|
|
|
620
608
|
// Backlog files
|
|
621
|
-
const
|
|
622
|
-
for (const file of backlogFiles) {
|
|
609
|
+
for (const file of ["backlog.md", "backlog-settings.md"]) {
|
|
623
610
|
const destPath = path.join(gsdtDir, file);
|
|
624
611
|
if (isSymlink(destPath)) {
|
|
625
612
|
warn(`Skipping .gsd-t/${file} — target is a symlink`);
|
|
@@ -634,13 +621,33 @@ function doInit(projectName) {
|
|
|
634
621
|
else { throw e; }
|
|
635
622
|
}
|
|
636
623
|
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function doInit(projectName) {
|
|
627
|
+
if (!projectName) {
|
|
628
|
+
projectName = path.basename(process.cwd());
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (!validateProjectName(projectName)) {
|
|
632
|
+
error(`Invalid project name: "${projectName}"`);
|
|
633
|
+
info("Project names must start with a letter or number and contain only letters, numbers, dots, hyphens, underscores, or spaces (max 101 chars)");
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
heading(`Initializing GSD-T project: ${projectName}`);
|
|
638
|
+
log("");
|
|
639
|
+
|
|
640
|
+
const projectDir = process.cwd();
|
|
641
|
+
const today = new Date().toISOString().split("T")[0];
|
|
642
|
+
|
|
643
|
+
initClaudeMd(projectDir, projectName, today);
|
|
644
|
+
initDocs(projectDir, projectName, today);
|
|
645
|
+
initGsdtDir(projectDir, projectName, today);
|
|
637
646
|
|
|
638
|
-
// 4. Register in project index
|
|
639
647
|
if (registerProject(projectDir)) {
|
|
640
648
|
success("Registered in ~/.claude/.gsd-t-projects");
|
|
641
649
|
}
|
|
642
650
|
|
|
643
|
-
// 5. Summary
|
|
644
651
|
heading("Project Initialized!");
|
|
645
652
|
log("");
|
|
646
653
|
log(` ${projectDir}/`);
|
|
@@ -773,8 +780,10 @@ function doUninstall() {
|
|
|
773
780
|
const commands = getInstalledCommands();
|
|
774
781
|
let removed = 0;
|
|
775
782
|
for (const file of commands) {
|
|
783
|
+
const fp = path.join(COMMANDS_DIR, file);
|
|
784
|
+
if (isSymlink(fp)) { warn(`Skipping symlink: ${file}`); continue; }
|
|
776
785
|
try {
|
|
777
|
-
fs.unlinkSync(
|
|
786
|
+
fs.unlinkSync(fp);
|
|
778
787
|
removed++;
|
|
779
788
|
} catch (e) {
|
|
780
789
|
error(`Failed to remove ${file}: ${e.message}`);
|
|
@@ -786,7 +795,7 @@ function doUninstall() {
|
|
|
786
795
|
|
|
787
796
|
// Remove version file
|
|
788
797
|
try {
|
|
789
|
-
if (fs.existsSync(VERSION_FILE)) {
|
|
798
|
+
if (fs.existsSync(VERSION_FILE) && !isSymlink(VERSION_FILE)) {
|
|
790
799
|
fs.unlinkSync(VERSION_FILE);
|
|
791
800
|
}
|
|
792
801
|
} catch (e) {
|
|
@@ -971,13 +980,8 @@ function doUpdateAll() {
|
|
|
971
980
|
log("");
|
|
972
981
|
}
|
|
973
982
|
|
|
974
|
-
function
|
|
975
|
-
heading("GSD-T Doctor");
|
|
976
|
-
log("");
|
|
977
|
-
|
|
983
|
+
function checkDoctorEnvironment() {
|
|
978
984
|
let issues = 0;
|
|
979
|
-
|
|
980
|
-
// 1. Node version
|
|
981
985
|
const nodeVersion = parseInt(process.version.slice(1));
|
|
982
986
|
if (nodeVersion >= 16) {
|
|
983
987
|
success(`Node.js ${process.version}`);
|
|
@@ -985,8 +989,6 @@ function doDoctor() {
|
|
|
985
989
|
error(`Node.js ${process.version} — requires >= 16`);
|
|
986
990
|
issues++;
|
|
987
991
|
}
|
|
988
|
-
|
|
989
|
-
// 2. Claude Code installed?
|
|
990
992
|
try {
|
|
991
993
|
const claudeVersion = execFileSync("claude", ["--version"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
992
994
|
success(`Claude Code: ${claudeVersion}`);
|
|
@@ -995,8 +997,6 @@ function doDoctor() {
|
|
|
995
997
|
info("Install with: npm install -g @anthropic-ai/claude-code");
|
|
996
998
|
issues++;
|
|
997
999
|
}
|
|
998
|
-
|
|
999
|
-
// 3. ~/.claude/ exists?
|
|
1000
1000
|
if (fs.existsSync(CLAUDE_DIR)) {
|
|
1001
1001
|
success("~/.claude/ directory exists");
|
|
1002
1002
|
} else {
|
|
@@ -1004,8 +1004,11 @@ function doDoctor() {
|
|
|
1004
1004
|
info("Run 'npx @tekyzinc/gsd-t install' to create it");
|
|
1005
1005
|
issues++;
|
|
1006
1006
|
}
|
|
1007
|
+
return issues;
|
|
1008
|
+
}
|
|
1007
1009
|
|
|
1008
|
-
|
|
1010
|
+
function checkDoctorInstallation() {
|
|
1011
|
+
let issues = 0;
|
|
1009
1012
|
const installed = getInstalledCommands();
|
|
1010
1013
|
const expected = getCommandFiles();
|
|
1011
1014
|
if (installed.length === expected.length) {
|
|
@@ -1019,8 +1022,6 @@ function doDoctor() {
|
|
|
1019
1022
|
error("No GSD-T commands installed");
|
|
1020
1023
|
issues++;
|
|
1021
1024
|
}
|
|
1022
|
-
|
|
1023
|
-
// 5. CLAUDE.md
|
|
1024
1025
|
if (fs.existsSync(GLOBAL_CLAUDE_MD)) {
|
|
1025
1026
|
const content = fs.readFileSync(GLOBAL_CLAUDE_MD, "utf8");
|
|
1026
1027
|
if (content.includes("GSD-T")) {
|
|
@@ -1033,8 +1034,6 @@ function doDoctor() {
|
|
|
1033
1034
|
error("No global CLAUDE.md");
|
|
1034
1035
|
issues++;
|
|
1035
1036
|
}
|
|
1036
|
-
|
|
1037
|
-
// 6. settings.json valid?
|
|
1038
1037
|
if (fs.existsSync(SETTINGS_JSON)) {
|
|
1039
1038
|
try {
|
|
1040
1039
|
JSON.parse(fs.readFileSync(SETTINGS_JSON, "utf8"));
|
|
@@ -1046,8 +1045,25 @@ function doDoctor() {
|
|
|
1046
1045
|
} else {
|
|
1047
1046
|
info("No settings.json (not required)");
|
|
1048
1047
|
}
|
|
1048
|
+
let encodingIssues = 0;
|
|
1049
|
+
for (const file of installed) {
|
|
1050
|
+
const content = fs.readFileSync(path.join(COMMANDS_DIR, file), "utf8");
|
|
1051
|
+
if (content.includes("\u00e2\u20ac") || content.includes("\u00c3")) {
|
|
1052
|
+
encodingIssues++;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
if (encodingIssues > 0) {
|
|
1056
|
+
error(`${encodingIssues} command files have encoding issues (corrupted characters)`);
|
|
1057
|
+
info("Run 'npx @tekyzinc/gsd-t update' to replace with clean versions");
|
|
1058
|
+
issues++;
|
|
1059
|
+
} else if (installed.length > 0) {
|
|
1060
|
+
success("No encoding issues in command files");
|
|
1061
|
+
}
|
|
1062
|
+
return issues;
|
|
1063
|
+
}
|
|
1049
1064
|
|
|
1050
|
-
|
|
1065
|
+
function checkDoctorProject() {
|
|
1066
|
+
let issues = 0;
|
|
1051
1067
|
const cwd = process.cwd();
|
|
1052
1068
|
if (hasPlaywright(cwd)) {
|
|
1053
1069
|
success("Playwright configured");
|
|
@@ -1056,8 +1072,6 @@ function doDoctor() {
|
|
|
1056
1072
|
info("Will be auto-installed when you run a GSD-T testing command");
|
|
1057
1073
|
issues++;
|
|
1058
1074
|
}
|
|
1059
|
-
|
|
1060
|
-
// 8. Swagger/OpenAPI check (current project)
|
|
1061
1075
|
if (hasApi(cwd)) {
|
|
1062
1076
|
if (hasSwagger(cwd)) {
|
|
1063
1077
|
success("Swagger/OpenAPI configured");
|
|
@@ -1069,24 +1083,16 @@ function doDoctor() {
|
|
|
1069
1083
|
} else {
|
|
1070
1084
|
info("No API framework detected (Swagger check skipped)");
|
|
1071
1085
|
}
|
|
1086
|
+
return issues;
|
|
1087
|
+
}
|
|
1072
1088
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
if (encodingIssues > 0) {
|
|
1082
|
-
error(`${encodingIssues} command files have encoding issues (corrupted characters)`);
|
|
1083
|
-
info("Run 'npx @tekyzinc/gsd-t update' to replace with clean versions");
|
|
1084
|
-
issues++;
|
|
1085
|
-
} else if (installed.length > 0) {
|
|
1086
|
-
success("No encoding issues in command files");
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// Summary
|
|
1089
|
+
function doDoctor() {
|
|
1090
|
+
heading("GSD-T Doctor");
|
|
1091
|
+
log("");
|
|
1092
|
+
let issues = 0;
|
|
1093
|
+
issues += checkDoctorEnvironment();
|
|
1094
|
+
issues += checkDoctorInstallation();
|
|
1095
|
+
issues += checkDoctorProject();
|
|
1090
1096
|
log("");
|
|
1091
1097
|
if (issues === 0) {
|
|
1092
1098
|
log(`${GREEN}${BOLD} All checks passed!${RESET}`);
|
|
@@ -1175,24 +1181,8 @@ function checkForUpdates() {
|
|
|
1175
1181
|
} catch { /* timeout or network error — skip */ }
|
|
1176
1182
|
} else if (isStale) {
|
|
1177
1183
|
// Cache exists but stale — refresh in background (non-blocking)
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
const fs = require("fs");
|
|
1181
|
-
https.get("https://registry.npmjs.org/@tekyzinc/gsd-t/latest",
|
|
1182
|
-
{ timeout: 5000 }, (res) => {
|
|
1183
|
-
let d = "";
|
|
1184
|
-
res.on("data", (c) => d += c);
|
|
1185
|
-
res.on("end", () => {
|
|
1186
|
-
try {
|
|
1187
|
-
const v = JSON.parse(d).version;
|
|
1188
|
-
fs.writeFileSync(${JSON.stringify(UPDATE_CHECK_FILE)},
|
|
1189
|
-
JSON.stringify({ latest: v, timestamp: Date.now() }));
|
|
1190
|
-
} catch {}
|
|
1191
|
-
});
|
|
1192
|
-
}).on("error", () => {});
|
|
1193
|
-
`.replace(/\n/g, "");
|
|
1194
|
-
const { spawn } = require("child_process");
|
|
1195
|
-
const child = spawn(process.execPath, ["-e", script], {
|
|
1184
|
+
const updateScript = path.join(__dirname, "..", "scripts", "npm-update-check.js");
|
|
1185
|
+
const child = cpSpawn(process.execPath, [updateScript, UPDATE_CHECK_FILE], {
|
|
1196
1186
|
detached: true,
|
|
1197
1187
|
stdio: "ignore",
|
|
1198
1188
|
});
|
|
@@ -1213,7 +1203,8 @@ function showUpdateNotice(latest) {
|
|
|
1213
1203
|
function doChangelog() {
|
|
1214
1204
|
try {
|
|
1215
1205
|
if (process.platform === "win32") {
|
|
1216
|
-
//
|
|
1206
|
+
// SAFETY: CHANGELOG_URL is a hardcoded constant (line 43). If it ever becomes
|
|
1207
|
+
// dynamic/user-provided, this cmd.exe call would need URL validation to prevent injection.
|
|
1217
1208
|
execFileSync("cmd", ["/c", "start", "", CHANGELOG_URL], { stdio: "ignore" });
|
|
1218
1209
|
} else {
|
|
1219
1210
|
const openCmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
@@ -175,9 +175,20 @@ Before creating the git tag, verify all documentation is up to date:
|
|
|
175
175
|
|
|
176
176
|
### This is the LAST GATE before tagging — nothing should be undocumented.
|
|
177
177
|
|
|
178
|
-
## Step 7.6: Test Verification
|
|
178
|
+
## Step 7.6: Spawn QA Agent and Test Verification
|
|
179
179
|
|
|
180
|
-
Before creating the git tag,
|
|
180
|
+
Before creating the git tag, spawn the QA teammate for a final test audit:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
184
|
+
Phase context: complete-milestone. Read .gsd-t/contracts/ for contract definitions.
|
|
185
|
+
Run final test audit before milestone archive. Verify all contract tests pass.
|
|
186
|
+
Report: final test pass/fail counts and any unresolved gaps.
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Wait for QA agent to complete. QA failure blocks milestone completion.
|
|
190
|
+
|
|
191
|
+
Then verify the milestone is truly complete:
|
|
181
192
|
|
|
182
193
|
1. **Run the full test suite**: Execute ALL tests — unit, integration, and E2E
|
|
183
194
|
2. **Run Playwright E2E** (if configured): Detect `playwright.config.*` or Playwright in dependencies. If present, run the full Playwright suite. If specs are missing or stale, invoke `gsd-t-test-sync` first.
|
package/commands/gsd-t-debug.md
CHANGED
|
@@ -40,6 +40,19 @@ The contract didn't specify something it should have. Symptoms:
|
|
|
40
40
|
|
|
41
41
|
→ Update the contract, then fix implementations on both sides.
|
|
42
42
|
|
|
43
|
+
## Step 2.5: Spawn QA Agent
|
|
44
|
+
|
|
45
|
+
Spawn the QA teammate to handle regression testing:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
49
|
+
Phase context: debug. Read .gsd-t/contracts/ for relevant contracts.
|
|
50
|
+
Write a regression test for the bug once root cause is identified.
|
|
51
|
+
Report: regression test status and related test coverage.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
QA failure blocks the commit.
|
|
55
|
+
|
|
43
56
|
## Step 3: Debug (Solo or Team)
|
|
44
57
|
|
|
45
58
|
### Solo Mode
|
|
@@ -19,6 +19,19 @@ Identify:
|
|
|
19
19
|
- Which tasks are unblocked (no pending dependencies)
|
|
20
20
|
- Which tasks are blocked (waiting on checkpoints)
|
|
21
21
|
|
|
22
|
+
## Step 1.5: Spawn QA Agent
|
|
23
|
+
|
|
24
|
+
Spawn the QA teammate to handle testing alongside execution:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
28
|
+
Phase context: execute. Read .gsd-t/contracts/ for contract definitions.
|
|
29
|
+
Run tests continuously as tasks complete. Write edge case tests for new code paths.
|
|
30
|
+
Report: test pass/fail status after each task completion.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The QA agent runs in parallel — it writes and executes tests while you implement tasks. QA failure on any task blocks proceeding to the next task.
|
|
34
|
+
|
|
22
35
|
## Step 2: Choose Execution Mode
|
|
23
36
|
|
|
24
37
|
### Solo Mode (default)
|
|
@@ -79,6 +92,10 @@ Teammate assignments:
|
|
|
79
92
|
- Teammate "{domain-1}": Execute .gsd-t/domains/{domain-1}/tasks.md
|
|
80
93
|
- Teammate "{domain-2}": Execute .gsd-t/domains/{domain-2}/tasks.md
|
|
81
94
|
- Teammate "{domain-3}": Execute .gsd-t/domains/{domain-3}/tasks.md
|
|
95
|
+
- Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
96
|
+
Phase context: execute. Read .gsd-t/contracts/ for contract definitions.
|
|
97
|
+
Run tests continuously as tasks complete. Write edge case tests.
|
|
98
|
+
Report: test pass/fail status after each task completion.
|
|
82
99
|
|
|
83
100
|
Lead responsibilities:
|
|
84
101
|
- Use delegate mode (Shift+Tab)
|
package/commands/gsd-t-help.md
CHANGED
|
@@ -36,6 +36,7 @@ MILESTONE WORKFLOW [auto] = in wave
|
|
|
36
36
|
impact [auto] Analyze downstream effects before execution
|
|
37
37
|
execute [auto] Run tasks (solo or team mode)
|
|
38
38
|
test-sync [auto] Sync tests with code changes
|
|
39
|
+
qa [auto] QA agent — test generation, execution, gap reporting
|
|
39
40
|
integrate [auto] Wire domains together at boundaries
|
|
40
41
|
verify [auto] Run quality gates
|
|
41
42
|
complete-milestone [auto] Archive milestone + git tag
|
|
@@ -55,6 +56,7 @@ UTILITIES Manual
|
|
|
55
56
|
log Sync progress Decision Log with recent git activity
|
|
56
57
|
version-update Update GSD-T package to latest version
|
|
57
58
|
version-update-all Update GSD-T package + all registered projects
|
|
59
|
+
triage-and-merge Auto-review, merge, and publish GitHub branches
|
|
58
60
|
|
|
59
61
|
BACKLOG Manual
|
|
60
62
|
───────────────────────────────────────────────────────────────────────────────
|
|
@@ -236,6 +238,12 @@ Use these when user asks for help on a specific command:
|
|
|
236
238
|
- **Creates**: `.gsd-t/test-coverage.md`, test tasks
|
|
237
239
|
- **Use when**: After code changes, to maintain test health
|
|
238
240
|
|
|
241
|
+
### qa
|
|
242
|
+
- **Summary**: QA agent — test generation, execution, and gap reporting
|
|
243
|
+
- **Auto-invoked**: Yes (spawned as teammate by partition, plan, execute, verify, quick, debug, integrate, complete-milestone)
|
|
244
|
+
- **Creates**: Contract test skeletons, acceptance tests, edge case tests, test audit reports
|
|
245
|
+
- **Use when**: Automatically spawned — never needs manual invocation. Standalone use for ad-hoc test audits.
|
|
246
|
+
|
|
239
247
|
### integrate
|
|
240
248
|
- **Summary**: Wire domains together at their boundaries
|
|
241
249
|
- **Auto-invoked**: Yes (in wave, after execute)
|
|
@@ -303,6 +311,13 @@ Use these when user asks for help on a specific command:
|
|
|
303
311
|
- **Use when**: Progress.md Decision Log is behind — catches up by scanning git commits since the last logged entry
|
|
304
312
|
- **Features**: Incremental updates, first-time full reconstruction from git history, groups same-day changes
|
|
305
313
|
|
|
314
|
+
### triage-and-merge
|
|
315
|
+
- **Summary**: Auto-review unmerged GitHub branches, merge safe ones, and optionally publish
|
|
316
|
+
- **Auto-invoked**: No
|
|
317
|
+
- **Files**: Reads `CLAUDE.md`, `.gsd-t/progress.md`, `package.json`; updates `package.json`, `.gsd-t/progress.md`, `CHANGELOG.md`
|
|
318
|
+
- **Use when**: Collaborators have pushed branches and you want to batch-review, merge, and publish without manual per-branch ceremony
|
|
319
|
+
- **Features**: 3-tier impact scoring (auto-merge / review / skip), publish gate (auto in Level 3, prompted otherwise), conflict detection, sensitive file detection
|
|
320
|
+
|
|
306
321
|
### backlog-add
|
|
307
322
|
- **Summary**: Capture a new backlog item with auto-categorization
|
|
308
323
|
- **Auto-invoked**: No
|
|
@@ -88,6 +88,19 @@ Result: PASS
|
|
|
88
88
|
Result: PARTIAL — needs pagination contract addition
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
## Step 4.5: Spawn QA Agent
|
|
92
|
+
|
|
93
|
+
Spawn the QA teammate to verify contract compliance at domain boundaries:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
97
|
+
Phase context: integrate. Read .gsd-t/contracts/ for all contract definitions.
|
|
98
|
+
Run contract compliance tests at every domain boundary.
|
|
99
|
+
Report: boundary-by-boundary test results.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
QA failure blocks integration completion.
|
|
103
|
+
|
|
91
104
|
## Step 5: Document Ripple
|
|
92
105
|
|
|
93
106
|
Integration is where the real system takes shape. Verify documentation matches reality:
|
|
@@ -175,6 +175,19 @@ Before finalizing the partition:
|
|
|
175
175
|
2. **Verify passing**: If any tests fail, assign them to the appropriate domain as pre-existing issues
|
|
176
176
|
3. **Map tests to domains**: Note which test files belong to which domain — this informs task planning
|
|
177
177
|
|
|
178
|
+
## Step 4.7: Spawn QA Agent
|
|
179
|
+
|
|
180
|
+
After contracts are written, spawn the QA teammate to generate contract test skeletons:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
184
|
+
Phase context: partition. Read .gsd-t/contracts/ for contract definitions.
|
|
185
|
+
Generate contract test skeleton files for every contract.
|
|
186
|
+
Report: number of test files generated and total test cases.
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Wait for QA agent to complete before proceeding. QA failure blocks partition completion.
|
|
190
|
+
|
|
178
191
|
## Step 5: Validate
|
|
179
192
|
|
|
180
193
|
Before finishing, verify:
|
package/commands/gsd-t-plan.md
CHANGED
|
@@ -118,6 +118,19 @@ Before finalizing the plan:
|
|
|
118
118
|
2. **Verify passing**: Document any pre-existing failures — assign them to appropriate domain tasks
|
|
119
119
|
3. **Include test tasks**: Ensure each domain's task list includes test creation/update tasks where acceptance criteria require verification
|
|
120
120
|
|
|
121
|
+
## Step 4.7: Spawn QA Agent
|
|
122
|
+
|
|
123
|
+
After task lists are created, spawn the QA teammate to generate acceptance test scenarios:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Teammate "qa": Read commands/gsd-t-qa.md for your full instructions.
|
|
127
|
+
Phase context: plan. Read .gsd-t/domains/*/tasks.md for task lists.
|
|
128
|
+
Generate acceptance test scenarios for tasks with user-facing deliverables.
|
|
129
|
+
Report: number of acceptance test scenarios generated.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Wait for QA agent to complete before proceeding.
|
|
133
|
+
|
|
121
134
|
## Step 5: Update Progress
|
|
122
135
|
|
|
123
136
|
Update `.gsd-t/progress.md`:
|