@tekyzinc/gsd-t 3.20.10 โ†’ 3.20.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 CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [3.20.12] - 2026-05-05
6
+
7
+ ### Fixed โ€” install: auto-configure M43 D1 + M45 D2 in-session hooks
8
+
9
+ `gsd-t install` did not deploy or wire up the M43 D1 token-usage hook (`gsd-t-in-session-usage-hook.js`) or the M45 D2 conversation-capture hook (`gsd-t-conversation-capture.js`), even though the global CLAUDE.md "In-Session Conversation Capture" section documented these as mandatory. Result: the dashboard's `/transcripts` left rail never showed `๐Ÿ’ฌ conversation` entries for in-session orchestrator dialog (this conversation right now); discovered when the live chat feed showed "no spawns yet" while the project's `.gsd-t/transcripts/` was missing entirely.
10
+
11
+ **Changes:**
12
+ - `bin/gsd-t.js`: new `installInSessionHooks()` + `configureInSessionHooks()` functions copy `scripts/hooks/gsd-t-conversation-capture.js` and `scripts/hooks/gsd-t-in-session-usage-hook.js` to `~/.claude/scripts/hooks/`, then register them in `~/.claude/settings.json` on the right events:
13
+ - `gsd-t-conversation-capture.js` โ†’ SessionStart, UserPromptSubmit, Stop (PostToolUse stays opt-in via the `GSD_T_CAPTURE_TOOL_USES=1` env flag)
14
+ - `gsd-t-in-session-usage-hook.js` โ†’ Stop
15
+ - New install heading **In-Session Hooks (Conversation Capture + Token Usage)** runs in the install pipeline immediately after Auto-Route.
16
+ - `test/filesystem.test.js`: bumped command-count assertions (54 โ†’ 55, utility 5 โ†’ 6) for the `cpua.md` command added in this session.
17
+
18
+ **Migration:** existing installs pick up the wiring on next `gsd-t update-all` or `gsd-t install` run. The configure step is idempotent; re-running is safe. Suite: 2042/2042 pass.
19
+
20
+ **Why this matters:** the conversation-capture hook is the only thing that lets you scroll back through your visualizer's `/transcripts` view and see chat with Claude in this session โ€” without it, the dashboard's left rail is permanently empty for the in-session conversation. The token-usage hook records per-turn cost so the meter and economics dashboards have real data.
21
+
22
+ ## [3.20.11] - 2026-05-05
23
+
24
+ ### Fixed โ€” install: ship `gsd-t-token-capture.cjs` to every project
25
+
26
+ `bin/gsd-t.js::PROJECT_BIN_TOOLS` was missing `gsd-t-token-capture.cjs` โ€” the wrapper that the **Token Capture Rule (MANDATORY)** in `CLAUDE.md` requires every Task spawn to flow through. Result: `gsd-t init` and `gsd-t update-all` shipped 11 other `bin/*.cjs` runtime files but silently skipped this one. Discovered when an audit of 18 registered projects found 15 of them missing the wrapper at `bin/gsd-t-token-capture.cjs` โ€” the contract was effectively advisory in installed projects.
27
+
28
+ **Changes:**
29
+ - `bin/gsd-t.js`: `PROJECT_BIN_TOOLS` now includes `gsd-t-token-capture.cjs`.
30
+ - `test/m41-canonical-block-drift.test.js`: new regression test asserts the wrapper is in `PROJECT_BIN_TOOLS`. Catches the same bug if it ever re-emerges (e.g., array reformat clobbers an entry).
31
+
32
+ **Migration:** existing projects fix automatically on next `gsd-t update-all` run โ€” the wrapper gets copied alongside the other bin tools. Test suite 2042/2042 pass.
33
+
5
34
  ## [3.20.10] - 2026-05-03
6
35
 
7
36
  ### Added โ€” Live-clock dated banner + PreToolUse date guard
package/bin/gsd-t.js CHANGED
@@ -936,6 +936,106 @@ function configureAutoRouteHook(scriptPath) {
936
936
  }
937
937
  }
938
938
 
939
+ // โ”€โ”€โ”€ In-Session Hooks (M43 D1 token usage + M45 D2 conversation capture) โ”€โ”€โ”€โ”€
940
+
941
+ const HOOKS_DIR = path.join(SCRIPTS_DIR, "hooks");
942
+ const PKG_HOOKS = path.join(PKG_SCRIPTS, "hooks");
943
+
944
+ // Each entry: { script, events, async } โ€” `events` is the array of hook event
945
+ // names this script must be wired into. The `gsd-t-conversation-capture.js`
946
+ // hook runs on SessionStart, UserPromptSubmit, and Stop (per the global
947
+ // CLAUDE.md M45 D2 install block โ€” PostToolUse stays opt-in via the
948
+ // GSD_T_CAPTURE_TOOL_USES env flag, so we don't auto-register it).
949
+ // `gsd-t-in-session-usage-hook.js` runs on Stop (per M43 D1 contract).
950
+ const IN_SESSION_HOOKS = [
951
+ {
952
+ script: "gsd-t-conversation-capture.js",
953
+ events: ["SessionStart", "UserPromptSubmit", "Stop"],
954
+ async: true,
955
+ },
956
+ {
957
+ script: "gsd-t-in-session-usage-hook.js",
958
+ events: ["Stop"],
959
+ async: true,
960
+ },
961
+ ];
962
+
963
+ function installInSessionHooks() {
964
+ ensureDir(SCRIPTS_DIR);
965
+ ensureDir(HOOKS_DIR);
966
+
967
+ if (!fs.existsSync(PKG_HOOKS)) {
968
+ info("No scripts/hooks/ in package โ€” skipping in-session hooks");
969
+ return;
970
+ }
971
+
972
+ // Copy each script into ~/.claude/scripts/hooks/
973
+ for (const hook of IN_SESSION_HOOKS) {
974
+ const src = path.join(PKG_HOOKS, hook.script);
975
+ const dest = path.join(HOOKS_DIR, hook.script);
976
+ if (!fs.existsSync(src)) {
977
+ warn(`In-session hook source missing: ${hook.script} โ€” skipping`);
978
+ continue;
979
+ }
980
+ const srcContent = fs.readFileSync(src, "utf8");
981
+ const destContent = fs.existsSync(dest) ? fs.readFileSync(dest, "utf8") : "";
982
+ if (normalizeEol(srcContent) !== normalizeEol(destContent)) {
983
+ copyFile(src, dest, `hooks/${hook.script}`);
984
+ try { fs.chmodSync(dest, 0o755); } catch {}
985
+ } else {
986
+ info(`In-session hook unchanged: ${hook.script}`);
987
+ }
988
+ }
989
+
990
+ configureInSessionHooks();
991
+ }
992
+
993
+ function configureInSessionHooks() {
994
+ const parsed = readSettingsJson();
995
+ if (parsed === null && fs.existsSync(SETTINGS_JSON)) {
996
+ warn("settings.json has invalid JSON โ€” cannot configure in-session hooks");
997
+ return;
998
+ }
999
+ const settings = parsed || {};
1000
+ if (!settings.hooks) settings.hooks = {};
1001
+
1002
+ let added = 0;
1003
+ for (const hook of IN_SESSION_HOOKS) {
1004
+ const scriptPath = path.join(HOOKS_DIR, hook.script);
1005
+ const cmd = `node "${scriptPath.replace(/\\/g, "\\\\")}"`;
1006
+
1007
+ for (const event of hook.events) {
1008
+ if (!settings.hooks[event]) settings.hooks[event] = [];
1009
+ const already = settings.hooks[event].some((entry) =>
1010
+ entry.hooks && entry.hooks.some((h) => h.command && h.command.includes(hook.script))
1011
+ );
1012
+ if (already) continue;
1013
+ const hookEntry = { type: "command", command: cmd };
1014
+ if (hook.async) hookEntry.async = true;
1015
+ settings.hooks[event].push({
1016
+ matcher: "",
1017
+ hooks: [hookEntry],
1018
+ });
1019
+ added++;
1020
+ }
1021
+ }
1022
+
1023
+ if (added === 0) {
1024
+ info("In-session hooks already configured");
1025
+ return;
1026
+ }
1027
+ if (isSymlink(SETTINGS_JSON)) {
1028
+ warn("Skipping settings.json write โ€” target is a symlink");
1029
+ return;
1030
+ }
1031
+ try {
1032
+ fs.writeFileSync(SETTINGS_JSON, JSON.stringify(settings, null, 2));
1033
+ success(`${added} in-session hook entr${added === 1 ? "y" : "ies"} configured in settings.json`);
1034
+ } catch (e) {
1035
+ warn(`Failed to write settings.json: ${e.message}`);
1036
+ }
1037
+ }
1038
+
939
1039
  // โ”€โ”€โ”€ Figma MCP โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
940
1040
 
941
1041
  const FIGMA_MCP_URL = "https://mcp.figma.com/mcp";
@@ -1321,6 +1421,9 @@ async function doInstall(opts = {}) {
1321
1421
  heading("Auto-Route (UserPromptSubmit)");
1322
1422
  installAutoRoute();
1323
1423
 
1424
+ heading("In-Session Hooks (Conversation Capture + Token Usage)");
1425
+ installInSessionHooks();
1426
+
1324
1427
  heading("Figma MCP (Design-to-Code)");
1325
1428
  configureFigmaMcp();
1326
1429
 
@@ -2178,6 +2281,7 @@ function updateSingleProject(projectDir, counts) {
2178
2281
  const PROJECT_BIN_TOOLS = [
2179
2282
  "archive-progress.cjs", "log-tail.cjs", "context-budget-audit.cjs",
2180
2283
  "context-meter-config.cjs", "token-budget.cjs",
2284
+ "gsd-t-token-capture.cjs",
2181
2285
  "gsd-t-unattended.cjs", "gsd-t-unattended-platform.cjs", "gsd-t-unattended-safety.cjs",
2182
2286
  "handoff-lock.cjs", "headless-auto-spawn.cjs",
2183
2287
  "headless-exit-codes.cjs",
@@ -0,0 +1,155 @@
1
+ # CPUA โ€” Commit, Publish, Update All
2
+
3
+ You are running the GSD-T release flow: commit pending in-tree changes, bump the version, publish to npm, tag the release, push to origin, and propagate to all registered projects.
4
+
5
+ This is a **scoped release command** โ€” only run in the GSD-T source repo (`/Users/david/projects/GSD-T` or whichever directory hosts `package.json` with `"name": "@tekyzinc/gsd-t"`). If invoked elsewhere, abort with a clear error.
6
+
7
+ ## Step 0: Verify scope
8
+
9
+ ```bash
10
+ node -e "
11
+ const pkg = require('./package.json');
12
+ if (pkg.name !== '@tekyzinc/gsd-t') {
13
+ console.error('ERROR: /cpua must be run from the GSD-T source repo. Current dir is not @tekyzinc/gsd-t.');
14
+ process.exit(1);
15
+ }
16
+ console.log('Scope OK โ€” releasing', pkg.name, 'v' + pkg.version);
17
+ "
18
+ ```
19
+
20
+ If this exits non-zero, stop and tell the user.
21
+
22
+ ## Step 1: Pre-flight checks
23
+
24
+ Before staging anything:
25
+
26
+ 1. **Run the test suite.** A failing suite blocks the release. Show the result count.
27
+ ```bash
28
+ npm test 2>&1 | tail -10
29
+ ```
30
+ 2. **Show the pending changes** so the user can scan what's about to be committed:
31
+ ```bash
32
+ git status -s
33
+ git diff --stat
34
+ ```
35
+ 3. **Decide the version bump** based on the nature of changes (semver per `~/.claude/CLAUDE.md` ยง Versioning):
36
+ - **Patch** (`x.y.10` โ†’ `x.y.11`) โ€” bug fix, doc fix, minor improvement
37
+ - **Minor** (`x.y.zz` โ†’ `x.(y+1).10`) โ€” new feature, new capability, behavior addition
38
+ - **Major** (`x.y.zz` โ†’ `(x+1).0.10`) โ€” breaking change, major rework
39
+ - Patch numbers always โ‰ฅ 10 (per the patch-2-digit convention).
40
+
41
+ If the bump is ambiguous (e.g., the changes mix bug fix + new feature), ask the user which they want; default to the higher bump if the user doesn't answer immediately.
42
+
43
+ 4. **Stop if any of these are true:**
44
+ - Test suite has failures
45
+ - Working tree is clean (nothing to commit โ€” tell user "nothing to release")
46
+ - Current branch is not `main` (warn user; ask before proceeding)
47
+ - There are unstaged changes outside the GSD-T scope (e.g., `.gsd-t/.unattended/run.log`, `.gsd-t/headless-*.log`, `.gsd-t/events/*.jsonl`) โ€” these are runtime noise and should NOT be committed. Stage explicitly by file, never `git add -A`.
48
+
49
+ ## Step 2: Stage, version-bump, and update CHANGELOG + progress.md
50
+
51
+ 1. **Stage only relevant files explicitly** โ€” `git add path1 path2 ...`. Never `git add -A` or `git add .` (would scoop up runtime logs).
52
+ 2. **Bump `package.json`** version to the new value.
53
+ 3. **Add a CHANGELOG entry** at the top, immediately under the header. Use this format:
54
+ ```markdown
55
+ ## [NEW_VERSION] - YYYY-MM-DD
56
+
57
+ ### {Added|Fixed|Changed|Removed} โ€” {one-line summary}
58
+
59
+ {2-4 sentences explaining what + why. Bullet the file-level changes.}
60
+
61
+ - `path/to/file`: {what changed}
62
+ - `path/to/test`: {regression test added if applicable}
63
+
64
+ {migration note if any}
65
+ ```
66
+ Use the live system clock for the date โ€” pull from `[GSD-T NOW]` or `node -e "console.log(new Date().toISOString().slice(0,10))"`. Never use `currentDate`.
67
+ 4. **Append a Decision Log entry** to `.gsd-t/progress.md` under `## Decision Log`. Format:
68
+ ```
69
+ - YYYY-MM-DD HH:MM: [tag] {summary} (vNEW_VERSION) โ€” {what changed and why}.
70
+ ```
71
+ Tag is one of: `[fix]`, `[feature]`, `[refactor]`, `[docs]`, `[chore]`, `[release]`.
72
+ 5. **Update `.gsd-t/progress.md` header** โ€” bump the `## Date:` to today and `## Version:` to NEW_VERSION.
73
+ 6. **Stage** the CHANGELOG and progress.md changes too.
74
+
75
+ ## Step 3: Commit
76
+
77
+ ```bash
78
+ git commit -m "$(cat <<'EOF'
79
+ {type}({scope}): {short summary} (v{NEW_VERSION})
80
+
81
+ {2-3 sentences explaining the change and motivation.}
82
+
83
+ - {file}: {change}
84
+ - {file}: {change}
85
+
86
+ Suite: N/N pass.
87
+
88
+ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
89
+ EOF
90
+ )"
91
+ ```
92
+
93
+ `{type}` is `fix` | `feat` | `chore` | `docs` | `refactor` per the convention seen in `git log --oneline`. `{scope}` is a short module/area identifier (e.g., `install`, `banner`, `parallel`).
94
+
95
+ ## Step 4: Tag and push
96
+
97
+ ```bash
98
+ git tag v{NEW_VERSION}
99
+ git push origin main --tags
100
+ ```
101
+
102
+ If push fails (auth, network, conflict), surface the error and stop โ€” do NOT publish a version that's not in origin.
103
+
104
+ ## Step 5: Publish to npm
105
+
106
+ ```bash
107
+ npm publish --access public 2>&1 | tail -10
108
+ ```
109
+
110
+ Verify the output shows `+ @tekyzinc/gsd-t@{NEW_VERSION}`. If publish fails:
111
+ - Auth issue โ†’ tell user to `npm login` and retry
112
+ - Version already published โ†’ version bump was wrong; redo Step 2 with a higher version
113
+ - Network โ†’ retry once, then surface the error
114
+
115
+ ## Step 6: Update global install + propagate to projects
116
+
117
+ ```bash
118
+ npm install -g @tekyzinc/gsd-t@{NEW_VERSION}
119
+ gsd-t update-all 2>&1 | tail -30
120
+ ```
121
+
122
+ Use `npm install -g @tekyzinc/gsd-t@{NEW_VERSION}` (NOT `npm update -g`) โ€” npm rejects update for some legacy version strings (e.g., `3.19.00` is invalid semver because of the leading-zero patch). Pinning to the exact version sidesteps this.
123
+
124
+ ## Step 7: Report
125
+
126
+ Print a concise summary:
127
+
128
+ ```
129
+ โœ… CPUA complete โ€” v{OLD} โ†’ v{NEW}
130
+
131
+ Commit: {short_sha} {commit message subject}
132
+ Tag: v{NEW}
133
+ Pushed: origin/main + tags
134
+ npm: @tekyzinc/gsd-t@{NEW} published
135
+ Global: {old global version} โ†’ v{NEW}
136
+ Projects: N updated, M already current
137
+
138
+ Test suite: N/N pass โ€” zero regressions.
139
+ ```
140
+
141
+ If anything failed, surface the specific step + error and tell the user what to do next.
142
+
143
+ ## Behavior
144
+
145
+ - **Always interactive on the version bump decision** โ€” unless the user pre-specified the bump in `$ARGUMENTS` (e.g., `/cpua patch` or `/cpua minor`).
146
+ - **Never `git add -A`** โ€” explicitly stage by file. Runtime logs and event streams stay out.
147
+ - **Never amend commits** โ€” if anything goes wrong post-commit, create a new commit. (Per global CLAUDE.md.)
148
+ - **Never skip Step 1 pre-flight** โ€” a broken release worse than a delayed one.
149
+ - **Always use the live system clock** for CHANGELOG and progress.md dates โ€” `[GSD-T NOW]` or `node -e "..."`.
150
+
151
+ $ARGUMENTS
152
+
153
+ ## Auto-Clear
154
+
155
+ All work is committed and propagated. Execute `/clear` to free the context window for the next command.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "3.20.10",
3
+ "version": "3.20.12",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code โ€” 54 slash commands with headless-by-default workflow spawning, unattended supervisor relay with event stream, graph-powered code analysis, real-time agent dashboard, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",