@tekyzinc/gsd-t 3.13.16 → 3.16.11

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +1 -0
  3. package/bin/gsd-t-benchmark-orchestrator.js +437 -0
  4. package/bin/gsd-t-capture-lint.cjs +276 -0
  5. package/bin/gsd-t-completion-check.cjs +106 -0
  6. package/bin/gsd-t-orchestrator-config.cjs +64 -0
  7. package/bin/gsd-t-orchestrator-queue.cjs +180 -0
  8. package/bin/gsd-t-orchestrator-recover.cjs +231 -0
  9. package/bin/gsd-t-orchestrator-worker.cjs +219 -0
  10. package/bin/gsd-t-orchestrator.js +534 -0
  11. package/bin/gsd-t-stream-feed-client.cjs +151 -0
  12. package/bin/gsd-t-task-brief-compactor.cjs +89 -0
  13. package/bin/gsd-t-task-brief-template.cjs +96 -0
  14. package/bin/gsd-t-task-brief.js +249 -0
  15. package/bin/gsd-t-token-backfill.cjs +366 -0
  16. package/bin/gsd-t-token-capture.cjs +306 -0
  17. package/bin/gsd-t-token-dashboard.cjs +318 -0
  18. package/bin/gsd-t-token-regenerate-log.cjs +129 -0
  19. package/bin/gsd-t-transcript-tee.cjs +246 -0
  20. package/bin/gsd-t-unattended-heartbeat.cjs +188 -0
  21. package/bin/gsd-t-unattended-platform.cjs +191 -27
  22. package/bin/gsd-t-unattended-safety.cjs +8 -1
  23. package/bin/gsd-t-unattended.cjs +192 -31
  24. package/bin/gsd-t.js +329 -2
  25. package/bin/supervisor-pid-fingerprint.cjs +126 -0
  26. package/commands/gsd-t-debug.md +63 -51
  27. package/commands/gsd-t-design-decompose.md +2 -7
  28. package/commands/gsd-t-doc-ripple.md +20 -11
  29. package/commands/gsd-t-execute.md +82 -50
  30. package/commands/gsd-t-integrate.md +43 -16
  31. package/commands/gsd-t-plan.md +20 -7
  32. package/commands/gsd-t-prd.md +19 -12
  33. package/commands/gsd-t-quick.md +64 -29
  34. package/commands/gsd-t-resume.md +51 -4
  35. package/commands/gsd-t-unattended.md +19 -20
  36. package/commands/gsd-t-verify.md +48 -32
  37. package/commands/gsd-t-visualize.md +19 -17
  38. package/commands/gsd-t-wave.md +29 -27
  39. package/docs/architecture.md +16 -0
  40. package/docs/m40-benchmark-report.md +35 -0
  41. package/docs/requirements.md +20 -0
  42. package/package.json +1 -1
  43. package/scripts/gsd-t-dashboard-server.js +291 -4
  44. package/scripts/gsd-t-dashboard.html +31 -1
  45. package/scripts/gsd-t-design-review-server.js +3 -1
  46. package/scripts/gsd-t-stream-feed-server.js +428 -0
  47. package/scripts/gsd-t-stream-feed.html +1168 -0
  48. package/scripts/gsd-t-token-aggregator.js +373 -0
  49. package/scripts/gsd-t-transcript.html +422 -0
  50. package/scripts/hooks/gsd-t-in-session-probe.js +62 -0
  51. package/scripts/hooks/pre-commit-capture-lint +26 -0
  52. package/templates/CLAUDE-global.md +69 -0
  53. package/scripts/gsd-t-agent-dashboard-server.js +0 -424
  54. package/scripts/gsd-t-agent-dashboard.html +0 -1043
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ const DROP_ORDER = Object.freeze([
4
+ 'stackRules',
5
+ 'contractExcerpts',
6
+ 'constraintsExtra'
7
+ ]);
8
+
9
+ const NON_DROPPABLE = Object.freeze([
10
+ 'preamble',
11
+ 'taskStatement',
12
+ 'scope',
13
+ 'constraintsMustFollow',
14
+ 'completionSpec',
15
+ 'cwdInvariant'
16
+ ]);
17
+
18
+ class TaskBriefTooLarge extends Error {
19
+ constructor(msg, breakdown) {
20
+ super(msg);
21
+ this.name = 'TaskBriefTooLarge';
22
+ this.breakdown = breakdown;
23
+ }
24
+ }
25
+
26
+ function byteLength(str) {
27
+ return Buffer.byteLength(str || '', 'utf8');
28
+ }
29
+
30
+ function computeBreakdown(sections) {
31
+ const breakdown = {};
32
+ let total = 0;
33
+ for (const k of Object.keys(sections)) {
34
+ const b = byteLength(sections[k]);
35
+ breakdown[k] = b;
36
+ total += b;
37
+ }
38
+ breakdown.__total = total;
39
+ return breakdown;
40
+ }
41
+
42
+ function compactToTarget(sections, maxBytes) {
43
+ if (!sections || typeof sections !== 'object') {
44
+ throw new Error('compactToTarget requires sections object');
45
+ }
46
+ if (typeof maxBytes !== 'number' || maxBytes <= 0) {
47
+ throw new Error('compactToTarget requires maxBytes > 0');
48
+ }
49
+
50
+ const out = { ...sections };
51
+ const total = () => {
52
+ let sum = 0;
53
+ for (const k of Object.keys(out)) sum += byteLength(out[k]);
54
+ return sum;
55
+ };
56
+
57
+ if (total() <= maxBytes) return out;
58
+
59
+ for (const key of DROP_ORDER) {
60
+ if (out[key]) {
61
+ out[key] = '';
62
+ if (total() <= maxBytes) return out;
63
+ }
64
+ }
65
+
66
+ const nonDroppable = {};
67
+ let ndTotal = 0;
68
+ for (const k of NON_DROPPABLE) {
69
+ const b = byteLength(out[k]);
70
+ nonDroppable[k] = b;
71
+ ndTotal += b;
72
+ }
73
+ if (ndTotal > maxBytes) {
74
+ throw new TaskBriefTooLarge(
75
+ `Non-droppable sections (${ndTotal} bytes) exceed maxBytes (${maxBytes})`,
76
+ { nonDroppable, maxBytes, ndTotal }
77
+ );
78
+ }
79
+
80
+ return out;
81
+ }
82
+
83
+ module.exports = {
84
+ compactToTarget,
85
+ TaskBriefTooLarge,
86
+ DROP_ORDER,
87
+ NON_DROPPABLE,
88
+ byteLength
89
+ };
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ const SECTION_HEADERS = Object.freeze({
4
+ task: '## Task',
5
+ scope: '## Scope',
6
+ constraints: '## Constraints',
7
+ contracts: '## Contracts',
8
+ stackRules: '## Stack Rules',
9
+ doneSignal: '## Done Signal',
10
+ cwd: '## CWD Invariant'
11
+ });
12
+
13
+ const CWD_INVARIANT_BODY = [
14
+ 'As your FIRST bash action, run: `pwd`',
15
+ 'If the output does not equal {projectDir}, STOP and fail fast. Do not proceed.',
16
+ 'If you must `cd` into a subdirectory, do it inside a subshell `(cd ... && ...)` so the parent cwd is preserved.'
17
+ ].join('\n');
18
+
19
+ const PREAMBLE_TEMPLATE = [
20
+ 'You are a GSD-T orchestrator worker. You have ONE task. You will not be asked to do anything else.',
21
+ '',
22
+ 'Project: {projectName}',
23
+ 'Milestone: {milestone}',
24
+ 'Domain: {domain}',
25
+ 'Task: {taskId}',
26
+ 'Expected branch: {expectedBranch}',
27
+ 'Project dir: {projectDir}',
28
+ '',
29
+ 'Operate under --dangerously-skip-permissions. Be autonomous. Do not ask questions. Commit your work on the expected branch before exiting.'
30
+ ].join('\n');
31
+
32
+ function renderPreamble(fields) {
33
+ const required = ['projectName', 'milestone', 'domain', 'taskId', 'expectedBranch', 'projectDir'];
34
+ for (const k of required) {
35
+ if (!fields || fields[k] == null || fields[k] === '') {
36
+ throw new Error(`renderPreamble requires ${k}`);
37
+ }
38
+ }
39
+ return PREAMBLE_TEMPLATE.replace(/\{(\w+)\}/g, (_, key) => fields[key]);
40
+ }
41
+
42
+ function renderCwdInvariant(projectDir) {
43
+ if (!projectDir) throw new Error('renderCwdInvariant requires projectDir');
44
+ return CWD_INVARIANT_BODY.replace('{projectDir}', projectDir);
45
+ }
46
+
47
+ function renderTemplate(sections) {
48
+ const {
49
+ preamble,
50
+ taskStatement,
51
+ scope,
52
+ constraints,
53
+ contractExcerpts,
54
+ stackRules,
55
+ completionSpec,
56
+ cwdInvariant
57
+ } = sections || {};
58
+
59
+ if (!preamble) throw new Error('renderTemplate requires preamble');
60
+ if (!taskStatement) throw new Error('renderTemplate requires taskStatement');
61
+ if (!scope) throw new Error('renderTemplate requires scope');
62
+ if (!constraints) throw new Error('renderTemplate requires constraints');
63
+ if (!completionSpec) throw new Error('renderTemplate requires completionSpec');
64
+ if (!cwdInvariant) throw new Error('renderTemplate requires cwdInvariant');
65
+
66
+ const parts = [
67
+ preamble,
68
+ '',
69
+ `${SECTION_HEADERS.task}\n${taskStatement.trim()}`,
70
+ '',
71
+ `${SECTION_HEADERS.scope}\n${scope.trim()}`,
72
+ '',
73
+ `${SECTION_HEADERS.constraints}\n${constraints.trim()}`
74
+ ];
75
+
76
+ if (contractExcerpts && contractExcerpts.trim()) {
77
+ parts.push('', `${SECTION_HEADERS.contracts}\n${contractExcerpts.trim()}`);
78
+ }
79
+ if (stackRules && stackRules.trim()) {
80
+ parts.push('', `${SECTION_HEADERS.stackRules}\n${stackRules.trim()}`);
81
+ }
82
+
83
+ parts.push('', `${SECTION_HEADERS.doneSignal}\n${completionSpec.trim()}`);
84
+ parts.push('', `${SECTION_HEADERS.cwd}\n${cwdInvariant.trim()}`);
85
+
86
+ return parts.join('\n') + '\n';
87
+ }
88
+
89
+ module.exports = {
90
+ SECTION_HEADERS,
91
+ CWD_INVARIANT_BODY,
92
+ PREAMBLE_TEMPLATE,
93
+ renderPreamble,
94
+ renderCwdInvariant,
95
+ renderTemplate
96
+ };
@@ -0,0 +1,249 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const {
6
+ renderPreamble,
7
+ renderCwdInvariant,
8
+ renderTemplate
9
+ } = require('./gsd-t-task-brief-template.cjs');
10
+ const {
11
+ compactToTarget,
12
+ TaskBriefTooLarge
13
+ } = require('./gsd-t-task-brief-compactor.cjs');
14
+
15
+ const DEFAULT_MAX_BYTES = 5000;
16
+
17
+ function readFileIfExists(fp) {
18
+ try { return fs.readFileSync(fp, 'utf8'); } catch (_) { return ''; }
19
+ }
20
+
21
+ function escapeForPrompt(s) {
22
+ return String(s).replace(/\r\n/g, '\n');
23
+ }
24
+
25
+ function extractTask(tasksMd, taskId) {
26
+ if (!tasksMd) return null;
27
+ const lines = tasksMd.split('\n');
28
+ const idMatch = /^d\d+-t(\d+)$/.exec(taskId) || /^([A-Za-z0-9_-]+)-?t?(\d+)$/i.exec(taskId);
29
+ const num = idMatch ? parseInt(idMatch[idMatch.length - 1], 10) : null;
30
+ if (num == null) return null;
31
+
32
+ const headerRe = new RegExp('^###\\s+Task\\s+' + num + '\\b');
33
+ let start = -1;
34
+ for (let i = 0; i < lines.length; i++) {
35
+ if (headerRe.test(lines[i])) { start = i; break; }
36
+ }
37
+ if (start < 0) return null;
38
+
39
+ let end = lines.length;
40
+ for (let i = start + 1; i < lines.length; i++) {
41
+ if (/^###\s+/.test(lines[i]) || /^##\s+/.test(lines[i])) { end = i; break; }
42
+ }
43
+ const body = lines.slice(start, end).join('\n').trim();
44
+ const contractRefs = [];
45
+ const refsMatch = /\*\*Contract refs\*\*:\s*(.+)/.exec(body);
46
+ if (refsMatch) {
47
+ for (const ref of refsMatch[1].split(',')) {
48
+ const trimmed = ref.trim().replace(/^`|`$/g, '');
49
+ if (trimmed && trimmed !== 'N/A') contractRefs.push(trimmed);
50
+ }
51
+ }
52
+ return { body, contractRefs };
53
+ }
54
+
55
+ function extractSection(md, headerRegex) {
56
+ if (!md) return '';
57
+ const lines = md.split('\n');
58
+ let start = -1;
59
+ for (let i = 0; i < lines.length; i++) {
60
+ if (headerRegex.test(lines[i])) { start = i + 1; break; }
61
+ }
62
+ if (start < 0) return '';
63
+ let end = lines.length;
64
+ for (let i = start; i < lines.length; i++) {
65
+ if (/^##\s+/.test(lines[i])) { end = i; break; }
66
+ }
67
+ return lines.slice(start, end).join('\n').trim();
68
+ }
69
+
70
+ function buildScopeSection(scopeMd) {
71
+ const owned = extractSection(scopeMd, /^##\s+Owned\s+Files/i);
72
+ const notOwned = extractSection(scopeMd, /^##\s+NOT\s+Owned/i);
73
+ const parts = [];
74
+ if (owned) parts.push('### Owned Files/Directories\n' + owned);
75
+ if (notOwned) parts.push('### NOT Owned (do not modify)\n' + notOwned);
76
+ return parts.join('\n\n');
77
+ }
78
+
79
+ function buildConstraintsSection(constraintsMd) {
80
+ const must = extractSection(constraintsMd, /^##\s+Must\s+Follow/i);
81
+ const mustNot = extractSection(constraintsMd, /^##\s+Must\s+Not/i);
82
+ const parts = [];
83
+ if (must) parts.push('### Must Follow\n' + must);
84
+ if (mustNot) parts.push('### Must Not\n' + mustNot);
85
+ return parts.join('\n\n');
86
+ }
87
+
88
+ function buildContractExcerpts(projectDir, contractRefs) {
89
+ if (!contractRefs || !contractRefs.length) return '';
90
+ const chunks = [];
91
+ for (const ref of contractRefs) {
92
+ const rel = ref.startsWith('.') ? ref : path.join('.gsd-t', 'contracts', path.basename(ref));
93
+ const abs = path.isAbsolute(rel) ? rel : path.join(projectDir, rel);
94
+ const content = readFileIfExists(abs);
95
+ if (!content) continue;
96
+ const firstLine = content.split('\n', 1)[0];
97
+ const title = firstLine.replace(/^#\s*/, '').trim() || path.basename(abs);
98
+ chunks.push('### ' + title + ' (' + path.basename(abs) + ')\n' + content.trim());
99
+ }
100
+ return chunks.join('\n\n');
101
+ }
102
+
103
+ function detectStack(projectDir) {
104
+ const stacks = [];
105
+ const pkgPath = path.join(projectDir, 'package.json');
106
+ if (fs.existsSync(pkgPath)) {
107
+ try {
108
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
109
+ const deps = Object.assign({}, pkg.dependencies || {}, pkg.devDependencies || {});
110
+ if (deps.react) stacks.push('react');
111
+ if (deps.typescript || deps['@types/node']) stacks.push('typescript');
112
+ if (deps.next) stacks.push('nextjs');
113
+ if (deps.vue) stacks.push('vue');
114
+ if (deps['@playwright/test'] || deps.playwright) stacks.push('playwright');
115
+ if (deps.express || deps.fastify || deps.hono) stacks.push('node-api');
116
+ if (deps.tailwindcss) stacks.push('tailwind');
117
+ if (deps.prisma || deps['@prisma/client']) stacks.push('prisma');
118
+ } catch (_) { /* ignore */ }
119
+ }
120
+ if (fs.existsSync(path.join(projectDir, 'requirements.txt')) ||
121
+ fs.existsSync(path.join(projectDir, 'pyproject.toml'))) {
122
+ stacks.push('python');
123
+ }
124
+ return stacks;
125
+ }
126
+
127
+ function loadStackRules(projectDir, stacks) {
128
+ const packageRoot = path.resolve(__dirname, '..');
129
+ const stacksDir = path.join(packageRoot, 'templates', 'stacks');
130
+ if (!fs.existsSync(stacksDir)) return '';
131
+ const universal = [];
132
+ for (const fname of fs.readdirSync(stacksDir).sort()) {
133
+ if (fname.startsWith('_') && fname.endsWith('.md')) {
134
+ universal.push(readFileIfExists(path.join(stacksDir, fname)).trim());
135
+ }
136
+ }
137
+ const specific = [];
138
+ for (const stack of stacks) {
139
+ const fp = path.join(stacksDir, stack + '.md');
140
+ if (fs.existsSync(fp)) specific.push(readFileIfExists(fp).trim());
141
+ }
142
+ return [...universal, ...specific].filter(Boolean).join('\n\n');
143
+ }
144
+
145
+ function buildCompletionSpec(projectDir) {
146
+ const contractFp = path.join(projectDir, '.gsd-t', 'contracts', 'completion-signal-contract.md');
147
+ const content = readFileIfExists(contractFp);
148
+ if (!content) {
149
+ throw new Error('buildTaskBrief requires .gsd-t/contracts/completion-signal-contract.md');
150
+ }
151
+ const doneSignal = extractSection(content, /^##\s+Done\s+Signal/i);
152
+ if (!doneSignal) {
153
+ throw new Error('completion-signal-contract.md missing ## Done Signal section');
154
+ }
155
+ return '### Done Signal (all must hold)\n' + doneSignal;
156
+ }
157
+
158
+ function readProjectName(projectDir) {
159
+ const pkgPath = path.join(projectDir, 'package.json');
160
+ if (fs.existsSync(pkgPath)) {
161
+ try {
162
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
163
+ if (pkg.name) return pkg.name;
164
+ } catch (_) { /* ignore */ }
165
+ }
166
+ return path.basename(projectDir);
167
+ }
168
+
169
+ function buildTaskBrief(opts) {
170
+ const {
171
+ milestone,
172
+ domain,
173
+ taskId,
174
+ projectDir,
175
+ expectedBranch = 'main',
176
+ maxBytes = DEFAULT_MAX_BYTES
177
+ } = opts || {};
178
+
179
+ if (!milestone) throw new Error('buildTaskBrief requires milestone');
180
+ if (!domain) throw new Error('buildTaskBrief requires domain');
181
+ if (!taskId) throw new Error('buildTaskBrief requires taskId');
182
+ if (!projectDir) throw new Error('buildTaskBrief requires projectDir');
183
+
184
+ const domainDir = path.join(projectDir, '.gsd-t', 'domains', domain);
185
+ if (!fs.existsSync(domainDir)) {
186
+ throw new Error('buildTaskBrief: domain dir not found: ' + domainDir);
187
+ }
188
+
189
+ const tasksMd = readFileIfExists(path.join(domainDir, 'tasks.md'));
190
+ const scopeMd = readFileIfExists(path.join(domainDir, 'scope.md'));
191
+ const constraintsMd = readFileIfExists(path.join(domainDir, 'constraints.md'));
192
+
193
+ const taskEntry = extractTask(tasksMd, taskId);
194
+ if (!taskEntry) {
195
+ throw new Error('buildTaskBrief: task not found in ' + domain + '/tasks.md: ' + taskId);
196
+ }
197
+
198
+ const projectName = readProjectName(projectDir);
199
+ const preamble = renderPreamble({
200
+ projectName: escapeForPrompt(projectName),
201
+ milestone: escapeForPrompt(milestone),
202
+ domain: escapeForPrompt(domain),
203
+ taskId: escapeForPrompt(taskId),
204
+ expectedBranch: escapeForPrompt(expectedBranch),
205
+ projectDir: escapeForPrompt(projectDir)
206
+ });
207
+
208
+ const cwdInvariant = renderCwdInvariant(projectDir);
209
+ const taskStatement = escapeForPrompt(taskEntry.body);
210
+ const scope = buildScopeSection(scopeMd) || '(no scope.md sections found)';
211
+ const constraints = buildConstraintsSection(constraintsMd) || '(no constraints.md sections found)';
212
+ const contractExcerpts = buildContractExcerpts(projectDir, taskEntry.contractRefs);
213
+ const stacks = detectStack(projectDir);
214
+ const stackRules = loadStackRules(projectDir, stacks);
215
+ const completionSpec = buildCompletionSpec(projectDir);
216
+
217
+ const sections = {
218
+ preamble,
219
+ taskStatement,
220
+ scope,
221
+ constraintsMustFollow: constraints,
222
+ contractExcerpts,
223
+ stackRules,
224
+ completionSpec,
225
+ cwdInvariant
226
+ };
227
+
228
+ const compacted = compactToTarget(sections, maxBytes);
229
+
230
+ return renderTemplate({
231
+ preamble: compacted.preamble,
232
+ taskStatement: compacted.taskStatement,
233
+ scope: compacted.scope,
234
+ constraints: compacted.constraintsMustFollow,
235
+ contractExcerpts: compacted.contractExcerpts,
236
+ stackRules: compacted.stackRules,
237
+ completionSpec: compacted.completionSpec,
238
+ cwdInvariant: compacted.cwdInvariant
239
+ });
240
+ }
241
+
242
+ module.exports = {
243
+ buildTaskBrief,
244
+ DEFAULT_MAX_BYTES,
245
+ TaskBriefTooLarge,
246
+ detectStack,
247
+ extractTask,
248
+ extractSection
249
+ };