@tekyzinc/gsd-t 2.24.7 → 2.28.12
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 +60 -0
- package/README.md +5 -3
- package/bin/gsd-t.js +80 -23
- package/commands/checkin.md +5 -1
- package/commands/gsd-t-complete-milestone.md +6 -16
- package/commands/gsd-t-debug.md +27 -13
- package/commands/gsd-t-discuss.md +28 -4
- package/commands/gsd-t-execute.md +45 -17
- package/commands/gsd-t-health.md +138 -0
- package/commands/gsd-t-help.md +2 -0
- package/commands/gsd-t-init-scan-setup.md +29 -6
- package/commands/gsd-t-init.md +40 -6
- package/commands/gsd-t-integrate.md +15 -6
- package/commands/gsd-t-partition.md +1 -14
- package/commands/gsd-t-pause.md +78 -0
- package/commands/gsd-t-plan.md +79 -9
- package/commands/gsd-t-quick.md +27 -13
- package/commands/gsd-t-resume.md +6 -3
- package/commands/gsd-t-scan.md +23 -5
- package/commands/gsd-t-status.md +17 -0
- package/commands/gsd-t-test-sync.md +8 -9
- package/commands/gsd-t-verify.md +15 -15
- package/commands/gsd-t-wave.md +9 -5
- package/docs/GSD-T-README.md +2 -0
- package/docs/architecture.md +54 -14
- package/docs/infrastructure.md +15 -7
- package/docs/requirements.md +17 -6
- package/docs/workflows.md +45 -5
- package/examples/settings.json +3 -2
- package/package.json +2 -2
- package/scripts/gsd-t-heartbeat.js +3 -3
- package/scripts/gsd-t-statusline.js +94 -0
- package/scripts/gsd-t-tools.js +163 -0
- package/templates/CLAUDE-global.md +24 -14
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// gsd-t-tools.js — GSD-T state utility CLI. Zero external dependencies.
|
|
4
|
+
// Returns compact JSON. Subcommands: state, validate, parse, list, git, template
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
// Find nearest .gsd-t/ directory walking up from cwd
|
|
10
|
+
function findProjectRoot() {
|
|
11
|
+
let dir = process.cwd();
|
|
12
|
+
while (dir !== path.dirname(dir)) {
|
|
13
|
+
if (fs.existsSync(path.join(dir, '.gsd-t'))) return dir;
|
|
14
|
+
dir = path.dirname(dir);
|
|
15
|
+
}
|
|
16
|
+
return process.cwd();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const root = findProjectRoot();
|
|
20
|
+
const gsdDir = path.join(root, '.gsd-t');
|
|
21
|
+
|
|
22
|
+
function readProgress() {
|
|
23
|
+
const p = path.join(gsdDir, 'progress.md');
|
|
24
|
+
if (!fs.existsSync(p)) return null;
|
|
25
|
+
return fs.readFileSync(p, 'utf8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function stateGet(key) {
|
|
29
|
+
const content = readProgress();
|
|
30
|
+
if (!content) return { error: 'progress.md not found' };
|
|
31
|
+
const re = new RegExp(`^## ${escapeRe(key)}:\\s*(.+)`, 'm');
|
|
32
|
+
const m = content.match(re);
|
|
33
|
+
if (!m) return { error: `key not found: ${key}` };
|
|
34
|
+
return { key, value: m[1].trim() };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function stateSet(key, value) {
|
|
38
|
+
const p = path.join(gsdDir, 'progress.md');
|
|
39
|
+
if (!fs.existsSync(p)) return { error: 'progress.md not found' };
|
|
40
|
+
const content = fs.readFileSync(p, 'utf8');
|
|
41
|
+
const re = new RegExp(`(^## ${escapeRe(key)}:\\s*)(.+)`, 'm');
|
|
42
|
+
if (!re.test(content)) return { error: `key not found: ${key}` };
|
|
43
|
+
fs.writeFileSync(p, content.replace(re, `$1${value}`));
|
|
44
|
+
return { ok: true, key, value };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validate() {
|
|
48
|
+
const required = [
|
|
49
|
+
'.gsd-t/progress.md',
|
|
50
|
+
'.gsd-t/contracts',
|
|
51
|
+
'.gsd-t/domains',
|
|
52
|
+
'CLAUDE.md',
|
|
53
|
+
];
|
|
54
|
+
const results = {};
|
|
55
|
+
const missing = [];
|
|
56
|
+
for (const f of required) {
|
|
57
|
+
const exists = fs.existsSync(path.join(root, f));
|
|
58
|
+
results[f] = exists ? 'ok' : 'missing';
|
|
59
|
+
if (!exists) missing.push(f);
|
|
60
|
+
}
|
|
61
|
+
return { valid: missing.length === 0, results, missing };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseSection(sectionName) {
|
|
65
|
+
const content = readProgress();
|
|
66
|
+
if (!content) return { error: 'progress.md not found' };
|
|
67
|
+
const re = new RegExp(`## ${escapeRe(sectionName)}\\n([\\s\\S]*?)(?=\\n## |$)`);
|
|
68
|
+
const m = content.match(re);
|
|
69
|
+
if (!m) return { error: `section not found: ${sectionName}` };
|
|
70
|
+
return { section: sectionName, content: m[1].trim() };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function listDomains() {
|
|
74
|
+
const dir = path.join(gsdDir, 'domains');
|
|
75
|
+
if (!fs.existsSync(dir)) return { domains: [] };
|
|
76
|
+
const domains = fs.readdirSync(dir).filter(f => {
|
|
77
|
+
try { return fs.statSync(path.join(dir, f)).isDirectory(); } catch { return false; }
|
|
78
|
+
});
|
|
79
|
+
return { domains };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function listContracts() {
|
|
83
|
+
const dir = path.join(gsdDir, 'contracts');
|
|
84
|
+
if (!fs.existsSync(dir)) return { contracts: [] };
|
|
85
|
+
const contracts = fs.readdirSync(dir).filter(f => f.endsWith('.md'));
|
|
86
|
+
return { contracts };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function preCommitCheck() {
|
|
90
|
+
const result = {};
|
|
91
|
+
try {
|
|
92
|
+
result.branch = execSync('git branch --show-current', { cwd: root, encoding: 'utf8' }).trim();
|
|
93
|
+
} catch {
|
|
94
|
+
result.branch = 'error';
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const status = execSync('git status --porcelain', { cwd: root, encoding: 'utf8' }).trim();
|
|
98
|
+
result.clean = status.length === 0;
|
|
99
|
+
result.changes = status ? status.split('\n').filter(Boolean) : [];
|
|
100
|
+
} catch {
|
|
101
|
+
result.clean = 'error';
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
result.lastCommit = execSync('git log -1 --format="%h %s"', { cwd: root, encoding: 'utf8' }).trim();
|
|
105
|
+
} catch {
|
|
106
|
+
result.lastCommit = 'error';
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function templateScope(domain) {
|
|
112
|
+
const p = path.join(gsdDir, 'domains', domain, 'scope.md');
|
|
113
|
+
if (!fs.existsSync(p)) return { error: `scope.md not found for domain: ${domain}` };
|
|
114
|
+
return { domain, scope: fs.readFileSync(p, 'utf8') };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function templateTasks(domain) {
|
|
118
|
+
const p = path.join(gsdDir, 'domains', domain, 'tasks.md');
|
|
119
|
+
if (!fs.existsSync(p)) return { error: `tasks.md not found for domain: ${domain}` };
|
|
120
|
+
return { domain, tasks: fs.readFileSync(p, 'utf8') };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function escapeRe(s) {
|
|
124
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Parse args
|
|
128
|
+
const args = process.argv.slice(2);
|
|
129
|
+
const [cmd, subcmd, ...rest] = args;
|
|
130
|
+
|
|
131
|
+
let result;
|
|
132
|
+
if (cmd === 'state') {
|
|
133
|
+
if (subcmd === 'get' && rest[0]) {
|
|
134
|
+
result = stateGet(rest[0]);
|
|
135
|
+
} else if (subcmd === 'set' && rest[0] && rest[1]) {
|
|
136
|
+
result = stateSet(rest[0], rest[1]);
|
|
137
|
+
} else {
|
|
138
|
+
result = { error: 'Usage: state get <key> | state set <key> <value>' };
|
|
139
|
+
}
|
|
140
|
+
} else if (cmd === 'validate') {
|
|
141
|
+
result = validate();
|
|
142
|
+
} else if (cmd === 'parse' && subcmd === 'progress') {
|
|
143
|
+
const si = args.indexOf('--section');
|
|
144
|
+
const section = si !== -1 ? args[si + 1] : null;
|
|
145
|
+
result = section ? parseSection(section) : { error: 'Usage: parse progress --section <name>' };
|
|
146
|
+
} else if (cmd === 'list') {
|
|
147
|
+
if (subcmd === 'domains') result = listDomains();
|
|
148
|
+
else if (subcmd === 'contracts') result = listContracts();
|
|
149
|
+
else result = { error: 'Usage: list domains | list contracts' };
|
|
150
|
+
} else if (cmd === 'git' && subcmd === 'pre-commit-check') {
|
|
151
|
+
result = preCommitCheck();
|
|
152
|
+
} else if (cmd === 'template') {
|
|
153
|
+
if (subcmd === 'scope' && rest[0]) result = templateScope(rest[0]);
|
|
154
|
+
else if (subcmd === 'tasks' && rest[0]) result = templateTasks(rest[0]);
|
|
155
|
+
else result = { error: 'Usage: template scope <domain> | template tasks <domain>' };
|
|
156
|
+
} else {
|
|
157
|
+
result = {
|
|
158
|
+
error: cmd ? `Unknown command: ${cmd}` : 'No command specified',
|
|
159
|
+
usage: 'state get|set validate parse progress --section <name> list domains|contracts git pre-commit-check template scope|tasks <domain>',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- GSD-T:START — Do not remove this marker. Content between START/END is managed by gsd-t update. -->
|
|
1
2
|
# Prime Directives
|
|
2
3
|
|
|
3
4
|
1. SIMPLICITY ABOVE ALL. Every change should be minimal and impact as little code as possible. No massive refactors.
|
|
@@ -54,6 +55,8 @@ PROJECT or FEATURE or SCAN
|
|
|
54
55
|
| `/user:gsd-t-status` | Cross-domain progress view |
|
|
55
56
|
| `/user:gsd-t-debug` | Systematic debugging |
|
|
56
57
|
| `/user:gsd-t-quick` | Fast task, respects contracts |
|
|
58
|
+
| `/user:gsd-t-health` | Validate .gsd-t/ structure, optionally repair |
|
|
59
|
+
| `/user:gsd-t-pause` | Save exact position for reliable resume |
|
|
57
60
|
| `/user:gsd-t-populate` | Auto-populate docs from existing codebase |
|
|
58
61
|
| `/user:gsd-t-log` | Sync progress Decision Log with recent git activity |
|
|
59
62
|
| `/user:gsd-t-resume` | Restore context, continue |
|
|
@@ -108,11 +111,13 @@ GSD-T tracks project version in `.gsd-t/progress.md` using semantic versioning:
|
|
|
108
111
|
|
|
109
112
|
| Segment | Bumped When | Example |
|
|
110
113
|
|---------|-------------|---------|
|
|
111
|
-
| **Major** | Breaking changes, major rework, v1 launch | 1.0.
|
|
112
|
-
| **Minor** | New features, completed feature milestones | 1.
|
|
113
|
-
| **Patch** | Bug fixes, minor improvements, cleanup | 1.1.
|
|
114
|
+
| **Major** | Breaking changes, major rework, v1 launch | 1.0.10 → 2.0.10 |
|
|
115
|
+
| **Minor** | New features, completed feature milestones | 1.10.10 → 1.11.10 |
|
|
116
|
+
| **Patch** | Bug fixes, minor improvements, cleanup | 1.1.10 → 1.1.11 |
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
**Patch convention**: Patch numbers are always 2 digits (≥10). When resetting after a minor or major bump, start at **10** (not 0). This keeps patches always 2 characters without leading zeros, so semver stays valid.
|
|
119
|
+
|
|
120
|
+
- Version is set during `gsd-t-init` (starts at `0.1.10`)
|
|
116
121
|
- Version is bumped during `gsd-t-complete-milestone` based on milestone scope
|
|
117
122
|
- Version is reflected in: `progress.md`, `README.md`, package manifest (if any), and git tags (`v{version}`)
|
|
118
123
|
|
|
@@ -221,20 +226,24 @@ This applies everywhere Playwright tests are executed: execute, test-sync, verif
|
|
|
221
226
|
|
|
222
227
|
## QA Agent (Mandatory)
|
|
223
228
|
|
|
224
|
-
Any GSD-T phase that produces or validates code **MUST
|
|
229
|
+
Any GSD-T phase that produces or validates code **MUST run QA**. The QA agent's sole job is test generation, execution, and gap reporting. It never writes feature code.
|
|
225
230
|
|
|
226
|
-
**
|
|
227
|
-
|
|
231
|
+
**QA method by command:**
|
|
232
|
+
- `execute`, `integrate` → spawn QA via **Task subagent** (lightweight, no TeamCreate)
|
|
233
|
+
- `test-sync`, `verify`, `complete-milestone` → perform contract testing and gap analysis **inline**
|
|
234
|
+
- `quick`, `debug` → run the full test suite **inline** as part of the command's Test & Verify step
|
|
235
|
+
- `wave` → each phase agent handles QA per the rules above
|
|
236
|
+
- `partition`, `plan` → no QA spawn needed (no code produced yet)
|
|
228
237
|
|
|
229
|
-
**
|
|
238
|
+
**Task subagent spawn instruction (execute/integrate):**
|
|
230
239
|
```
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
Task subagent (general-purpose):
|
|
241
|
+
"Run the full test suite and contract compliance tests.
|
|
242
|
+
Read .gsd-t/contracts/ for contract definitions.
|
|
243
|
+
Report: pass/fail counts and any coverage gaps."
|
|
235
244
|
```
|
|
236
245
|
|
|
237
|
-
**QA
|
|
246
|
+
**QA failure blocks phase completion.** Lead cannot proceed until QA reports PASS or user explicitly overrides.
|
|
238
247
|
|
|
239
248
|
## API Documentation Guard (Swagger/OpenAPI)
|
|
240
249
|
|
|
@@ -407,7 +416,7 @@ Successor mapping:
|
|
|
407
416
|
| `populate` | `status` | |
|
|
408
417
|
| `setup` | `status` | |
|
|
409
418
|
|
|
410
|
-
Commands with no successor (standalone): `quick`, `debug`, `brainstorm`, `status`, `help`, `resume`, `prompt`, `log`, backlog commands.
|
|
419
|
+
Commands with no successor (standalone): `quick`, `debug`, `brainstorm`, `status`, `help`, `resume`, `prompt`, `log`, `health`, `pause`, backlog commands.
|
|
411
420
|
|
|
412
421
|
Skip the hint if auto-advancing (Level 3 mid-wave) — only show when the user needs to manually invoke the next step.
|
|
413
422
|
|
|
@@ -456,3 +465,4 @@ When resuming work (new session or after /clear):
|
|
|
456
465
|
6. Continue from current task — don't restart the phase
|
|
457
466
|
|
|
458
467
|
**CRITICAL: Do NOT research how the system works. The docs tell you. Read them.**
|
|
468
|
+
<!-- GSD-T:END — Do not remove this marker. -->
|