@tekyzinc/gsd-t 2.50.12 → 2.53.10
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 +24 -0
- package/README.md +379 -372
- package/bin/component-registry.js +250 -0
- package/bin/graph-cgc.js +510 -510
- package/bin/graph-indexer.js +147 -147
- package/bin/graph-overlay.js +195 -195
- package/bin/graph-parsers.js +327 -327
- package/bin/graph-query.js +453 -452
- package/bin/graph-store.js +154 -154
- package/bin/qa-calibrator.js +194 -0
- package/bin/scan-data-collector.js +153 -153
- package/bin/scan-diagrams-generators.js +187 -187
- package/bin/scan-diagrams.js +79 -79
- package/bin/scan-renderer.js +92 -92
- package/bin/scan-report-sections.js +121 -121
- package/bin/scan-report.js +184 -184
- package/bin/scan-schema-parsers.js +199 -199
- package/bin/scan-schema.js +103 -103
- package/bin/token-budget.js +246 -0
- package/commands/Claude-md.md +10 -10
- package/commands/branch.md +15 -15
- package/commands/checkin.md +45 -45
- package/commands/global-change.md +209 -209
- package/commands/gsd-t-audit.md +199 -0
- package/commands/gsd-t-backlog-add.md +94 -94
- package/commands/gsd-t-backlog-edit.md +111 -111
- package/commands/gsd-t-backlog-list.md +63 -63
- package/commands/gsd-t-backlog-move.md +94 -94
- package/commands/gsd-t-backlog-promote.md +123 -123
- package/commands/gsd-t-backlog-remove.md +86 -86
- package/commands/gsd-t-backlog-settings.md +158 -158
- package/commands/gsd-t-complete-milestone.md +528 -515
- package/commands/gsd-t-debug.md +506 -399
- package/commands/gsd-t-discuss.md +174 -174
- package/commands/gsd-t-execute.md +758 -634
- package/commands/gsd-t-feature.md +276 -276
- package/commands/gsd-t-health.md +142 -142
- package/commands/gsd-t-help.md +465 -457
- package/commands/gsd-t-impact.md +302 -302
- package/commands/gsd-t-init.md +320 -280
- package/commands/gsd-t-integrate.md +365 -249
- package/commands/gsd-t-milestone.md +87 -87
- package/commands/gsd-t-partition.md +442 -361
- package/commands/gsd-t-pause.md +82 -82
- package/commands/gsd-t-plan.md +345 -344
- package/commands/gsd-t-populate.md +111 -111
- package/commands/gsd-t-prd.md +326 -326
- package/commands/gsd-t-project.md +211 -211
- package/commands/gsd-t-promote-debt.md +123 -123
- package/commands/gsd-t-prompt.md +137 -137
- package/commands/gsd-t-qa.md +266 -266
- package/commands/gsd-t-quick.md +357 -234
- package/commands/gsd-t-reflect.md +134 -134
- package/commands/gsd-t-resume.md +72 -72
- package/commands/gsd-t-scan.md +615 -615
- package/commands/gsd-t-setup.md +76 -0
- package/commands/gsd-t-status.md +192 -166
- package/commands/gsd-t-test-sync.md +381 -381
- package/commands/gsd-t-triage-and-merge.md +171 -171
- package/commands/gsd-t-verify.md +382 -382
- package/commands/gsd-t-visualize.md +118 -118
- package/commands/gsd-t-wave.md +401 -378
- package/docs/GSD-T-README.md +425 -422
- package/docs/architecture.md +385 -369
- package/docs/harness-design-analysis.md +371 -0
- package/docs/infrastructure.md +205 -205
- package/docs/prd-graph-engine.md +398 -398
- package/docs/prd-gsd2-hybrid.md +559 -559
- package/docs/prd-harness-evolution.md +583 -0
- package/docs/requirements.md +14 -0
- package/docs/workflows.md +226 -226
- package/examples/.gsd-t/domains/example-domain/scope.md +13 -13
- package/package.json +40 -40
- package/scripts/gsd-t-auto-route.js +39 -39
- package/scripts/gsd-t-dashboard-mockup.html +1143 -1143
- package/scripts/gsd-t-dashboard-server.js +171 -171
- package/scripts/gsd-t-dashboard.html +262 -262
- package/scripts/gsd-t-event-writer.js +128 -128
- package/scripts/gsd-t-statusline.js +94 -94
- package/scripts/gsd-t-tools.js +175 -175
- package/templates/CLAUDE-global.md +639 -614
- package/templates/CLAUDE-project.md +24 -0
- package/templates/backlog-settings.md +18 -18
- package/templates/backlog.md +1 -1
- package/templates/progress.md +40 -40
- package/templates/shared-services-contract.md +60 -60
- package/templates/stacks/desktop.ini +2 -2
- package/bin/desktop.ini +0 -2
- package/commands/desktop.ini +0 -2
- package/docs/ci-examples/desktop.ini +0 -2
- package/docs/desktop.ini +0 -2
- package/examples/.gsd-t/contracts/desktop.ini +0 -2
- package/examples/.gsd-t/desktop.ini +0 -2
- package/examples/.gsd-t/domains/desktop.ini +0 -2
- package/examples/.gsd-t/domains/example-domain/desktop.ini +0 -2
- package/examples/desktop.ini +0 -2
- package/examples/rules/desktop.ini +0 -2
- package/scripts/desktop.ini +0 -2
- package/templates/desktop.ini +0 -2
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* GSD-T Event Writer — Structured JSONL Event Appender
|
|
5
|
-
*
|
|
6
|
-
* Writes structured events to .gsd-t/events/YYYY-MM-DD.jsonl (UTC date rotation).
|
|
7
|
-
* CLI for use from hooks and command files.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* node gsd-t-event-writer.js --type phase_transition --command gsd-t-wave \
|
|
11
|
-
* --phase execute --reasoning "Execute complete" --outcome success \
|
|
12
|
-
* --agent-id "$SESSION" --parent-id null --trace-id "$TRACE"
|
|
13
|
-
*
|
|
14
|
-
* Exit codes: 0 = success, 1 = validation error, 2 = filesystem error
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const fs = require("fs");
|
|
18
|
-
const path = require("path");
|
|
19
|
-
|
|
20
|
-
// ─── Schema ──────────────────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
const VALID_EVENT_TYPES = new Set([
|
|
23
|
-
"command_invoked",
|
|
24
|
-
"phase_transition",
|
|
25
|
-
"subagent_spawn",
|
|
26
|
-
"subagent_complete",
|
|
27
|
-
"session_start",
|
|
28
|
-
"session_end",
|
|
29
|
-
"tool_call",
|
|
30
|
-
"experience_retrieval",
|
|
31
|
-
"outcome_tagged",
|
|
32
|
-
"distillation",
|
|
33
|
-
"task_complete",
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
const VALID_OUTCOMES = new Set(["success", "failure", "learning", "deferred", null]);
|
|
37
|
-
|
|
38
|
-
// ─── Exports (for testing) ────────────────────────────────────────────────────
|
|
39
|
-
module.exports = { validateEvent, resolveEventsFile, appendEvent };
|
|
40
|
-
|
|
41
|
-
// ─── CLI Entry ───────────────────────────────────────────────────────────────
|
|
42
|
-
if (require.main === module) {
|
|
43
|
-
const args = parseArgs(process.argv.slice(2));
|
|
44
|
-
const event = buildEvent(args);
|
|
45
|
-
const validationError = validateEvent(event);
|
|
46
|
-
if (validationError) {
|
|
47
|
-
process.stderr.write(validationError + "\n");
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
const projectDir = process.env.GSD_T_PROJECT_DIR || process.cwd();
|
|
51
|
-
const eventsFile = resolveEventsFile(projectDir);
|
|
52
|
-
const exitCode = appendEvent(eventsFile, event);
|
|
53
|
-
process.exit(exitCode);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ─── Arg Parsing ─────────────────────────────────────────────────────────────
|
|
57
|
-
|
|
58
|
-
function parseArgs(argv) {
|
|
59
|
-
const map = {};
|
|
60
|
-
for (let i = 0; i < argv.length - 1; i++) {
|
|
61
|
-
if (argv[i].startsWith("--")) {
|
|
62
|
-
map[argv[i].slice(2)] = argv[i + 1];
|
|
63
|
-
i++;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return map;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function nullify(val) {
|
|
70
|
-
return val === undefined || val === "null" ? null : val;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function buildEvent(args) {
|
|
74
|
-
return {
|
|
75
|
-
ts: new Date().toISOString(),
|
|
76
|
-
event_type: nullify(args["type"]),
|
|
77
|
-
command: nullify(args["command"]),
|
|
78
|
-
phase: nullify(args["phase"]),
|
|
79
|
-
agent_id: nullify(args["agent-id"]),
|
|
80
|
-
parent_agent_id: nullify(args["parent-id"]),
|
|
81
|
-
trace_id: nullify(args["trace-id"]),
|
|
82
|
-
reasoning: nullify(args["reasoning"]),
|
|
83
|
-
outcome: nullify(args["outcome"]),
|
|
84
|
-
model: nullify(args["model"]),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ─── Validation ──────────────────────────────────────────────────────────────
|
|
89
|
-
|
|
90
|
-
function validateEvent(event) {
|
|
91
|
-
if (!event || typeof event !== "object") return "Event must be an object";
|
|
92
|
-
if (!event.event_type) return "Missing required field: --type";
|
|
93
|
-
if (!VALID_EVENT_TYPES.has(event.event_type)) {
|
|
94
|
-
return `Invalid event_type: "${event.event_type}". Must be one of: ${[...VALID_EVENT_TYPES].join(", ")}`;
|
|
95
|
-
}
|
|
96
|
-
if (!VALID_OUTCOMES.has(event.outcome)) {
|
|
97
|
-
return `Invalid outcome: "${event.outcome}". Must be one of: success, failure, learning, deferred, null`;
|
|
98
|
-
}
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ─── File Resolution ──────────────────────────────────────────────────────────
|
|
103
|
-
|
|
104
|
-
function resolveEventsFile(projectDir) {
|
|
105
|
-
const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD UTC
|
|
106
|
-
return path.join(projectDir, ".gsd-t", "events", `${date}.jsonl`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ─── Append ───────────────────────────────────────────────────────────────────
|
|
110
|
-
|
|
111
|
-
function appendEvent(filePath, event) {
|
|
112
|
-
try {
|
|
113
|
-
const eventsDir = path.dirname(filePath);
|
|
114
|
-
if (!fs.existsSync(eventsDir)) {
|
|
115
|
-
fs.mkdirSync(eventsDir, { recursive: true });
|
|
116
|
-
}
|
|
117
|
-
// Symlink check — prevent writing to redirected files
|
|
118
|
-
try {
|
|
119
|
-
if (fs.lstatSync(filePath).isSymbolicLink()) return 2;
|
|
120
|
-
} catch {
|
|
121
|
-
// File doesn't exist yet — safe to create
|
|
122
|
-
}
|
|
123
|
-
fs.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
124
|
-
return 0;
|
|
125
|
-
} catch {
|
|
126
|
-
return 2;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GSD-T Event Writer — Structured JSONL Event Appender
|
|
5
|
+
*
|
|
6
|
+
* Writes structured events to .gsd-t/events/YYYY-MM-DD.jsonl (UTC date rotation).
|
|
7
|
+
* CLI for use from hooks and command files.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node gsd-t-event-writer.js --type phase_transition --command gsd-t-wave \
|
|
11
|
+
* --phase execute --reasoning "Execute complete" --outcome success \
|
|
12
|
+
* --agent-id "$SESSION" --parent-id null --trace-id "$TRACE"
|
|
13
|
+
*
|
|
14
|
+
* Exit codes: 0 = success, 1 = validation error, 2 = filesystem error
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require("fs");
|
|
18
|
+
const path = require("path");
|
|
19
|
+
|
|
20
|
+
// ─── Schema ──────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
const VALID_EVENT_TYPES = new Set([
|
|
23
|
+
"command_invoked",
|
|
24
|
+
"phase_transition",
|
|
25
|
+
"subagent_spawn",
|
|
26
|
+
"subagent_complete",
|
|
27
|
+
"session_start",
|
|
28
|
+
"session_end",
|
|
29
|
+
"tool_call",
|
|
30
|
+
"experience_retrieval",
|
|
31
|
+
"outcome_tagged",
|
|
32
|
+
"distillation",
|
|
33
|
+
"task_complete",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const VALID_OUTCOMES = new Set(["success", "failure", "learning", "deferred", null]);
|
|
37
|
+
|
|
38
|
+
// ─── Exports (for testing) ────────────────────────────────────────────────────
|
|
39
|
+
module.exports = { validateEvent, resolveEventsFile, appendEvent };
|
|
40
|
+
|
|
41
|
+
// ─── CLI Entry ───────────────────────────────────────────────────────────────
|
|
42
|
+
if (require.main === module) {
|
|
43
|
+
const args = parseArgs(process.argv.slice(2));
|
|
44
|
+
const event = buildEvent(args);
|
|
45
|
+
const validationError = validateEvent(event);
|
|
46
|
+
if (validationError) {
|
|
47
|
+
process.stderr.write(validationError + "\n");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const projectDir = process.env.GSD_T_PROJECT_DIR || process.cwd();
|
|
51
|
+
const eventsFile = resolveEventsFile(projectDir);
|
|
52
|
+
const exitCode = appendEvent(eventsFile, event);
|
|
53
|
+
process.exit(exitCode);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── Arg Parsing ─────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
function parseArgs(argv) {
|
|
59
|
+
const map = {};
|
|
60
|
+
for (let i = 0; i < argv.length - 1; i++) {
|
|
61
|
+
if (argv[i].startsWith("--")) {
|
|
62
|
+
map[argv[i].slice(2)] = argv[i + 1];
|
|
63
|
+
i++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return map;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function nullify(val) {
|
|
70
|
+
return val === undefined || val === "null" ? null : val;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildEvent(args) {
|
|
74
|
+
return {
|
|
75
|
+
ts: new Date().toISOString(),
|
|
76
|
+
event_type: nullify(args["type"]),
|
|
77
|
+
command: nullify(args["command"]),
|
|
78
|
+
phase: nullify(args["phase"]),
|
|
79
|
+
agent_id: nullify(args["agent-id"]),
|
|
80
|
+
parent_agent_id: nullify(args["parent-id"]),
|
|
81
|
+
trace_id: nullify(args["trace-id"]),
|
|
82
|
+
reasoning: nullify(args["reasoning"]),
|
|
83
|
+
outcome: nullify(args["outcome"]),
|
|
84
|
+
model: nullify(args["model"]),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ─── Validation ──────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
function validateEvent(event) {
|
|
91
|
+
if (!event || typeof event !== "object") return "Event must be an object";
|
|
92
|
+
if (!event.event_type) return "Missing required field: --type";
|
|
93
|
+
if (!VALID_EVENT_TYPES.has(event.event_type)) {
|
|
94
|
+
return `Invalid event_type: "${event.event_type}". Must be one of: ${[...VALID_EVENT_TYPES].join(", ")}`;
|
|
95
|
+
}
|
|
96
|
+
if (!VALID_OUTCOMES.has(event.outcome)) {
|
|
97
|
+
return `Invalid outcome: "${event.outcome}". Must be one of: success, failure, learning, deferred, null`;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─── File Resolution ──────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
function resolveEventsFile(projectDir) {
|
|
105
|
+
const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD UTC
|
|
106
|
+
return path.join(projectDir, ".gsd-t", "events", `${date}.jsonl`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── Append ───────────────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
function appendEvent(filePath, event) {
|
|
112
|
+
try {
|
|
113
|
+
const eventsDir = path.dirname(filePath);
|
|
114
|
+
if (!fs.existsSync(eventsDir)) {
|
|
115
|
+
fs.mkdirSync(eventsDir, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
// Symlink check — prevent writing to redirected files
|
|
118
|
+
try {
|
|
119
|
+
if (fs.lstatSync(filePath).isSymbolicLink()) return 2;
|
|
120
|
+
} catch {
|
|
121
|
+
// File doesn't exist yet — safe to create
|
|
122
|
+
}
|
|
123
|
+
fs.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
124
|
+
return 0;
|
|
125
|
+
} catch {
|
|
126
|
+
return 2;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
// gsd-t-statusline.js — GSD-T status line for Claude Code
|
|
4
|
-
// Outputs compact project status for display in Claude Code's statusLine setting.
|
|
5
|
-
//
|
|
6
|
-
// Configure in ~/.claude/settings.json:
|
|
7
|
-
// "statusLine": "node ~/.claude/scripts/gsd-t-statusline.js"
|
|
8
|
-
//
|
|
9
|
-
// Context usage is read from CLAUDE_CONTEXT_TOKENS_USED and
|
|
10
|
-
// CLAUDE_CONTEXT_TOKENS_MAX environment variables if available.
|
|
11
|
-
// Falls back to GSD-T project state only.
|
|
12
|
-
//
|
|
13
|
-
// Zero external dependencies.
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
|
|
18
|
-
// ─── ANSI colors ─────────────────────────────────────────────────────────────
|
|
19
|
-
const GREEN = '\x1b[32m';
|
|
20
|
-
const YELLOW = '\x1b[33m';
|
|
21
|
-
const RED = '\x1b[31m';
|
|
22
|
-
const RESET = '\x1b[0m';
|
|
23
|
-
const DIM = '\x1b[2m';
|
|
24
|
-
const BOLD = '\x1b[1m';
|
|
25
|
-
const ORANGE = '\x1b[38;5;208m'; // 256-color orange
|
|
26
|
-
|
|
27
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
function findProjectRoot() {
|
|
30
|
-
let dir = process.cwd();
|
|
31
|
-
while (dir !== path.dirname(dir)) {
|
|
32
|
-
if (fs.existsSync(path.join(dir, '.gsd-t'))) return dir;
|
|
33
|
-
dir = path.dirname(dir);
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function readProgress(root) {
|
|
39
|
-
const p = path.join(root, '.gsd-t', 'progress.md');
|
|
40
|
-
if (!fs.existsSync(p)) return null;
|
|
41
|
-
try { return fs.readFileSync(p, 'utf8'); } catch { return null; }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function extract(content, key) {
|
|
45
|
-
const m = content.match(new RegExp(`^## ${key}:\\s*(.+)`, 'm'));
|
|
46
|
-
return m ? m[1].trim() : null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function contextBar(pct) {
|
|
50
|
-
// pct: 0-100
|
|
51
|
-
const barLen = 10;
|
|
52
|
-
const filled = Math.round((pct / 100) * barLen);
|
|
53
|
-
const empty = barLen - filled;
|
|
54
|
-
let color;
|
|
55
|
-
if (pct < 50) color = GREEN;
|
|
56
|
-
else if (pct < 70) color = YELLOW;
|
|
57
|
-
else if (pct < 85) color = ORANGE;
|
|
58
|
-
else color = RED;
|
|
59
|
-
return `${color}${'█'.repeat(filled)}${DIM}${'░'.repeat(empty)}${RESET} ${color}${pct}%${RESET}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
63
|
-
|
|
64
|
-
const root = findProjectRoot();
|
|
65
|
-
|
|
66
|
-
// Context usage from env vars (provided by Claude Code if available)
|
|
67
|
-
const tokensUsed = parseInt(process.env.CLAUDE_CONTEXT_TOKENS_USED || '0', 10);
|
|
68
|
-
const tokensMax = parseInt(process.env.CLAUDE_CONTEXT_TOKENS_MAX || '0', 10);
|
|
69
|
-
const hasContext = tokensMax > 0;
|
|
70
|
-
const ctxPct = hasContext ? Math.min(100, Math.round((tokensUsed / tokensMax) * 100)) : null;
|
|
71
|
-
|
|
72
|
-
// GSD-T project state
|
|
73
|
-
let projectPart = '';
|
|
74
|
-
if (root) {
|
|
75
|
-
const content = readProgress(root);
|
|
76
|
-
if (content) {
|
|
77
|
-
const milestone = extract(content, 'Milestone') || extract(content, 'Current Milestone') || '—';
|
|
78
|
-
const status = extract(content, 'Status') || '—';
|
|
79
|
-
const version = extract(content, 'Version') || '';
|
|
80
|
-
const vStr = version ? ` ${DIM}v${version}${RESET}` : '';
|
|
81
|
-
projectPart = `${BOLD}${milestone}${RESET} ${DIM}${status}${RESET}${vStr}`;
|
|
82
|
-
}
|
|
83
|
-
} else {
|
|
84
|
-
projectPart = `${DIM}(no gsd-t project)${RESET}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Context bar
|
|
88
|
-
let contextPart = '';
|
|
89
|
-
if (ctxPct !== null) {
|
|
90
|
-
contextPart = ` │ ctx ${contextBar(ctxPct)}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const line = `gsd-t │ ${projectPart}${contextPart}`;
|
|
94
|
-
process.stdout.write(line + '\n');
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// gsd-t-statusline.js — GSD-T status line for Claude Code
|
|
4
|
+
// Outputs compact project status for display in Claude Code's statusLine setting.
|
|
5
|
+
//
|
|
6
|
+
// Configure in ~/.claude/settings.json:
|
|
7
|
+
// "statusLine": "node ~/.claude/scripts/gsd-t-statusline.js"
|
|
8
|
+
//
|
|
9
|
+
// Context usage is read from CLAUDE_CONTEXT_TOKENS_USED and
|
|
10
|
+
// CLAUDE_CONTEXT_TOKENS_MAX environment variables if available.
|
|
11
|
+
// Falls back to GSD-T project state only.
|
|
12
|
+
//
|
|
13
|
+
// Zero external dependencies.
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
// ─── ANSI colors ─────────────────────────────────────────────────────────────
|
|
19
|
+
const GREEN = '\x1b[32m';
|
|
20
|
+
const YELLOW = '\x1b[33m';
|
|
21
|
+
const RED = '\x1b[31m';
|
|
22
|
+
const RESET = '\x1b[0m';
|
|
23
|
+
const DIM = '\x1b[2m';
|
|
24
|
+
const BOLD = '\x1b[1m';
|
|
25
|
+
const ORANGE = '\x1b[38;5;208m'; // 256-color orange
|
|
26
|
+
|
|
27
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
function findProjectRoot() {
|
|
30
|
+
let dir = process.cwd();
|
|
31
|
+
while (dir !== path.dirname(dir)) {
|
|
32
|
+
if (fs.existsSync(path.join(dir, '.gsd-t'))) return dir;
|
|
33
|
+
dir = path.dirname(dir);
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readProgress(root) {
|
|
39
|
+
const p = path.join(root, '.gsd-t', 'progress.md');
|
|
40
|
+
if (!fs.existsSync(p)) return null;
|
|
41
|
+
try { return fs.readFileSync(p, 'utf8'); } catch { return null; }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function extract(content, key) {
|
|
45
|
+
const m = content.match(new RegExp(`^## ${key}:\\s*(.+)`, 'm'));
|
|
46
|
+
return m ? m[1].trim() : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function contextBar(pct) {
|
|
50
|
+
// pct: 0-100
|
|
51
|
+
const barLen = 10;
|
|
52
|
+
const filled = Math.round((pct / 100) * barLen);
|
|
53
|
+
const empty = barLen - filled;
|
|
54
|
+
let color;
|
|
55
|
+
if (pct < 50) color = GREEN;
|
|
56
|
+
else if (pct < 70) color = YELLOW;
|
|
57
|
+
else if (pct < 85) color = ORANGE;
|
|
58
|
+
else color = RED;
|
|
59
|
+
return `${color}${'█'.repeat(filled)}${DIM}${'░'.repeat(empty)}${RESET} ${color}${pct}%${RESET}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
const root = findProjectRoot();
|
|
65
|
+
|
|
66
|
+
// Context usage from env vars (provided by Claude Code if available)
|
|
67
|
+
const tokensUsed = parseInt(process.env.CLAUDE_CONTEXT_TOKENS_USED || '0', 10);
|
|
68
|
+
const tokensMax = parseInt(process.env.CLAUDE_CONTEXT_TOKENS_MAX || '0', 10);
|
|
69
|
+
const hasContext = tokensMax > 0;
|
|
70
|
+
const ctxPct = hasContext ? Math.min(100, Math.round((tokensUsed / tokensMax) * 100)) : null;
|
|
71
|
+
|
|
72
|
+
// GSD-T project state
|
|
73
|
+
let projectPart = '';
|
|
74
|
+
if (root) {
|
|
75
|
+
const content = readProgress(root);
|
|
76
|
+
if (content) {
|
|
77
|
+
const milestone = extract(content, 'Milestone') || extract(content, 'Current Milestone') || '—';
|
|
78
|
+
const status = extract(content, 'Status') || '—';
|
|
79
|
+
const version = extract(content, 'Version') || '';
|
|
80
|
+
const vStr = version ? ` ${DIM}v${version}${RESET}` : '';
|
|
81
|
+
projectPart = `${BOLD}${milestone}${RESET} ${DIM}${status}${RESET}${vStr}`;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
projectPart = `${DIM}(no gsd-t project)${RESET}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Context bar
|
|
88
|
+
let contextPart = '';
|
|
89
|
+
if (ctxPct !== null) {
|
|
90
|
+
contextPart = ` │ ctx ${contextBar(ctxPct)}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const line = `gsd-t │ ${projectPart}${contextPart}`;
|
|
94
|
+
process.stdout.write(line + '\n');
|