@tekyzinc/gsd-t 4.10.10 → 4.10.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 +26 -0
- package/README.md +1 -1
- package/bin/gsd-t-graph-edge-extract.cjs +15 -5
- package/bin/gsd-t-graph-freshness.cjs +15 -5
- package/bin/gsd-t-graph-index.cjs +6 -1
- package/bin/gsd-t-graph-query-cli.cjs +3 -3
- package/bin/gsd-t-require-store.cjs +89 -0
- package/bin/gsd-t.js +4 -0
- package/package.json +8 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [4.10.12] - 2026-06-27
|
|
6
|
+
|
|
7
|
+
### Fixed — freshness hash mismatch made every graph query re-index the whole repo
|
|
8
|
+
|
|
9
|
+
`compute_touched_files` hashed files with md5 (full length) while the indexer stores sha256 sliced to 16 chars — a guaranteed permanent mismatch. So every file read as "edited" on every query and freshness re-indexed the entire repo (re-running SCIP), hanging `gsd-t graph status` for 30s+ (then reporting graph-unavailable) on large projects.
|
|
10
|
+
|
|
11
|
+
- `bin/gsd-t-graph-freshness.cjs`: `hashFileContent` now `sha256().slice(0,16)` — matches the indexer's `contentHash` exactly. `EXCLUDE_DIRS` synced with the indexer's `SKIP_DIRS` (`.venv`/`site-packages`/etc.) so freshness doesn't see phantom ADDs from vendored dirs the indexer skipped.
|
|
12
|
+
- 5 D4 freshness test fixtures seeded stores with md5 hashes — updated to sha256(16) to match the real store.
|
|
13
|
+
|
|
14
|
+
Measured on Tekyz-CRM: `gsd-t graph status` 30s-timeout-unavailable → 0.38s ok; `compute_touched_files` 291ms / 11,821-files-stale → 12ms / 0-stale. This also makes graph queries cheap enough for ambient grep-interception (the next milestone). Suite: 2502/2502 pass.
|
|
15
|
+
|
|
16
|
+
## [4.10.11] - 2026-06-27
|
|
17
|
+
|
|
18
|
+
### Fixed — M96: the code graph now actually runs in projects (native-dep resolution)
|
|
19
|
+
|
|
20
|
+
M94/M95 copied the graph runtime into every project's `bin/`, but it couldn't run: the native engines (better-sqlite3 store + tree-sitter floor parsers) were `devDependencies`, and a copied tool resolved them from the *project's* node_modules — which lacked them. The result was a SILENT empty graph (0 nodes/edges that read as a successful build). M96 makes the graph runnable everywhere.
|
|
21
|
+
|
|
22
|
+
- `package.json`: moved `better-sqlite3` + `tree-sitter` + `tree-sitter-typescript` + `tree-sitter-python` from devDependencies to `dependencies` (they ship now).
|
|
23
|
+
- `bin/gsd-t-require-store.cjs`: NEW `requireGraphDep()` — resolves a native dep from project node_modules → GSD-T global package node_modules → GSD-T dev tree; FAIL LOUD with a remediation message if all miss.
|
|
24
|
+
- `bin/gsd-t-graph-edge-extract.cjs`: resolves tree-sitter via the resolver and THROWS (not silent-0) when the mandatory floor parser is absent.
|
|
25
|
+
- `bin/gsd-t-graph-{index,freshness,query-cli}.cjs`: store engine via the resolver.
|
|
26
|
+
- `bin/gsd-t.js`: propagate `gsd-t-require-store.cjs` to projects.
|
|
27
|
+
- `test/m50-d2-viewer-specs-smoke.test.js`: zero-dep invariant updated to allow ONLY the graph native engines as runtime deps.
|
|
28
|
+
|
|
29
|
+
Proven on binvoice (a real non-GSD-T project): graph builds 471 files / 43,309 edges; `blast-radius(src/build-config.ts)` returns its real dependents (the consumer reads the graph, not grep). Decision reaffirmed: zero-dependency is a guiding principle, not a hard rule — native deps are justified because the graph cannot function without them. Suite: 2502/2502 pass.
|
|
30
|
+
|
|
5
31
|
## [4.10.10] - 2026-06-26
|
|
6
32
|
|
|
7
33
|
### Added — M94 persistent code graph + M95 real SCIP call-graph resolution; graph runtime now propagates into projects
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Contract-Driven Development for Claude Code
|
|
2
2
|
|
|
3
|
-
**v4.10.
|
|
3
|
+
**v4.10.12** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
|
|
4
4
|
|
|
5
5
|
**Eliminates context rot** — task-level fresh dispatch (one subagent per task, ~10-20% context each) means compaction never triggers.
|
|
6
6
|
**Compaction-proof debug loops** — `gsd-t headless --debug-loop` runs test-fix-retest cycles as separate `claude -p` sessions. A JSONL debug ledger persists all hypothesis/fix/learning history across fresh sessions. Anti-repetition preamble injection prevents retrying failed hypotheses. Escalation tiers (sonnet → opus → human) and a hard iteration ceiling enforced externally.
|
|
@@ -63,19 +63,29 @@ let pythonAvailable = false;
|
|
|
63
63
|
function ensureParsers() {
|
|
64
64
|
if (_parsersLoaded) return;
|
|
65
65
|
_parsersLoaded = true;
|
|
66
|
+
// M96: resolve the tree-sitter native modules via the multi-location resolver so
|
|
67
|
+
// a COPIED extractor (in a project's bin/) finds them in the GSD-T global package,
|
|
68
|
+
// not the project's own (absent) node_modules. The TS grammar is the MANDATORY
|
|
69
|
+
// floor parser — if it cannot load, FAIL LOUD. A silent fall-through to
|
|
70
|
+
// tsAvailable=false produced an empty graph (0 nodes/edges) that looked like a
|
|
71
|
+
// successful build — the exact silent-degrade this milestone exists to kill.
|
|
72
|
+
const { requireGraphDep } = require('./gsd-t-require-store.cjs');
|
|
66
73
|
try {
|
|
67
|
-
Parser =
|
|
68
|
-
TSGrammars =
|
|
74
|
+
Parser = requireGraphDep('tree-sitter');
|
|
75
|
+
TSGrammars = requireGraphDep('tree-sitter-typescript');
|
|
69
76
|
TSX = TSGrammars.tsx;
|
|
70
77
|
tsAvailable = true;
|
|
71
78
|
} catch (e) {
|
|
72
|
-
|
|
79
|
+
throw new Error(
|
|
80
|
+
`code-graph floor parser unavailable: ${e.message} — the graph cannot be built ` +
|
|
81
|
+
`without tree-sitter. Reinstall GSD-T (npx @tekyzinc/gsd-t install).`
|
|
82
|
+
);
|
|
73
83
|
}
|
|
74
84
|
try {
|
|
75
|
-
Python =
|
|
85
|
+
Python = requireGraphDep('tree-sitter-python');
|
|
76
86
|
pythonAvailable = true;
|
|
77
87
|
} catch {
|
|
78
|
-
/* Python optional */
|
|
88
|
+
/* Python optional — TS/JS still index */
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
|
|
@@ -48,22 +48,32 @@ function fail(msg) { return `${C.red}✘${C.reset} ${msg}`; }
|
|
|
48
48
|
// ─── Source-file extensions the indexer tracks ────────────────────────────────
|
|
49
49
|
const TRACKED_EXTS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.jsx', '.py']);
|
|
50
50
|
|
|
51
|
-
// ─── Content-hash
|
|
52
|
-
//
|
|
53
|
-
//
|
|
51
|
+
// ─── Content-hash — MUST match the indexer's contentHash EXACTLY ─────────────
|
|
52
|
+
// The indexer (gsd-t-graph-index.cjs::contentHash) stores sha256(content) sliced
|
|
53
|
+
// to the first 16 hex chars. Freshness MUST compute the identical value, or EVERY
|
|
54
|
+
// file reads as "edited" on every query (the hash never matches) and freshness
|
|
55
|
+
// re-indexes the whole repo — the hang. (Was md5/full-length: a guaranteed
|
|
56
|
+
// permanent mismatch.) [RULE] freshness-hash-matches-indexer-hash
|
|
54
57
|
function hashFileContent(filePath) {
|
|
55
58
|
try {
|
|
56
59
|
const content = fs.readFileSync(filePath);
|
|
57
|
-
return crypto.createHash('
|
|
60
|
+
return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
58
61
|
} catch {
|
|
59
62
|
return null;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
// ─── Walk the working tree for source files ───────────────────────────────────
|
|
67
|
+
// MUST stay in sync with the indexer's SKIP_DIRS (gsd-t-graph-index.cjs). If
|
|
68
|
+
// freshness walks a dir the indexer skipped, every file in it reads as a phantom
|
|
69
|
+
// ADD on every query → re-index storm (bee-poc/Tekyz-CRM: 9,008 phantom adds from
|
|
70
|
+
// .venv + build bundles). [RULE] freshness-excludes-match-indexer-skipdirs
|
|
64
71
|
const EXCLUDE_DIRS = new Set([
|
|
65
72
|
'node_modules', '.git', 'dist', 'build', 'coverage',
|
|
66
73
|
'.gsd-t', '.claude', '__pycache__', '.next', 'out',
|
|
74
|
+
'.cache', '.nyc_output', '.turbo',
|
|
75
|
+
'.venv', 'venv', 'env', '.dart_tool', 'Pods', 'vendor', '.gradle',
|
|
76
|
+
'.idea', '.vscode', 'tmp', '.tmp', 'site-packages',
|
|
67
77
|
]);
|
|
68
78
|
|
|
69
79
|
function walkTree(dir, results = []) {
|
|
@@ -99,7 +109,7 @@ function walkTree(dir, results = []) {
|
|
|
99
109
|
// a single open connection. If no db is passed, we open one from projectRoot.
|
|
100
110
|
|
|
101
111
|
function openDb(projectRoot, explicitDbPath) {
|
|
102
|
-
const Database = require('
|
|
112
|
+
const Database = require('./gsd-t-require-store.cjs').requireBetterSqlite();
|
|
103
113
|
// Canonical store path is `.gsd-t/graph.db` (matches build_index's default,
|
|
104
114
|
// the query CLI, and .gitignore). Accept an explicit path when the caller
|
|
105
115
|
// already knows it (runFreshnessCheck passes the exact storePath).
|
|
@@ -70,6 +70,11 @@ const SKIP_DIRS = new Set([
|
|
|
70
70
|
'node_modules', '.next', 'dist', 'build', '.git',
|
|
71
71
|
'.cache', '__pycache__', 'coverage', '.nyc_output',
|
|
72
72
|
'out', '.turbo',
|
|
73
|
+
// M96 follow-up: vendored / generated trees that aren't project source and
|
|
74
|
+
// explode the file count (bee-poc had 18K files from .venv + iOS build assets,
|
|
75
|
+
// hanging scip-typescript at 8.5GB). Exclude language vendor/build dirs.
|
|
76
|
+
'.venv', 'venv', 'env', '.dart_tool', 'Pods', 'vendor', '.gradle',
|
|
77
|
+
'.idea', '.vscode', 'tmp', '.tmp', 'site-packages',
|
|
73
78
|
]);
|
|
74
79
|
|
|
75
80
|
// ── Content hash ──────────────────────────────────────────────────────────────
|
|
@@ -114,7 +119,7 @@ function enumerateFiles(root) {
|
|
|
114
119
|
* Returns a better-sqlite3 Database instance.
|
|
115
120
|
*/
|
|
116
121
|
function openStore(dbPath) {
|
|
117
|
-
const Database = require('
|
|
122
|
+
const Database = require('./gsd-t-require-store.cjs').requireBetterSqlite();
|
|
118
123
|
const db = new Database(dbPath);
|
|
119
124
|
db.pragma('journal_mode = WAL');
|
|
120
125
|
db.pragma('synchronous = NORMAL');
|
|
@@ -232,10 +232,10 @@ function loadSkippedFiles(storePath) {
|
|
|
232
232
|
}
|
|
233
233
|
if (!dbPath) return new Set();
|
|
234
234
|
|
|
235
|
-
//
|
|
235
|
+
// Load the graph store engine via the M96 multi-location resolver.
|
|
236
236
|
let Database;
|
|
237
237
|
try {
|
|
238
|
-
Database = require("
|
|
238
|
+
Database = require("./gsd-t-require-store.cjs").requireBetterSqlite();
|
|
239
239
|
} catch (_e) {
|
|
240
240
|
return new Set();
|
|
241
241
|
}
|
|
@@ -394,7 +394,7 @@ function buildIndex(records, skippedFiles) {
|
|
|
394
394
|
*/
|
|
395
395
|
function loadSqliteStore(dbPath) {
|
|
396
396
|
let Database;
|
|
397
|
-
try { Database = require("
|
|
397
|
+
try { Database = require("./gsd-t-require-store.cjs").requireBetterSqlite(); }
|
|
398
398
|
catch (_e) { return null; }
|
|
399
399
|
let db;
|
|
400
400
|
try {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gsd-t-require-store.cjs
|
|
3
|
+
*
|
|
4
|
+
* M96 — Robust resolver for the graph runtime's NATIVE dependencies
|
|
5
|
+
* (better-sqlite3, tree-sitter, tree-sitter-typescript, tree-sitter-python).
|
|
6
|
+
*
|
|
7
|
+
* The graph runtime tools (gsd-t-graph-index / -freshness / -query-cli /
|
|
8
|
+
* -edge-extract) are COPIED into each project's `bin/` by update-all. A copied
|
|
9
|
+
* tool's bare `require('better-sqlite3')` / `require('tree-sitter')` resolves
|
|
10
|
+
* from the PROJECT's node_modules — which usually lacks these native modules.
|
|
11
|
+
* This helper resolves a module from, in order:
|
|
12
|
+
* 1. the normal resolution from this file's location
|
|
13
|
+
* 2. the project's own node_modules (cwd-based)
|
|
14
|
+
* 3. the GSD-T global package's node_modules (where `dependencies` install)
|
|
15
|
+
* 4. the GSD-T dev tree (this repo), a last-resort dev fallback
|
|
16
|
+
*
|
|
17
|
+
* All four are GSD-T `dependencies` (M96), so candidate 3 is the normal hit for a
|
|
18
|
+
* propagated copy. FAIL LOUD with a remediation message if all miss — never a
|
|
19
|
+
* cryptic MODULE_NOT_FOUND, and never a SILENT degrade to an empty graph.
|
|
20
|
+
*
|
|
21
|
+
* [RULE] graph-native-dep-resolved-or-fail-loud
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
'use strict';
|
|
25
|
+
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
const { execSync } = require('node:child_process');
|
|
28
|
+
|
|
29
|
+
const _cache = new Map();
|
|
30
|
+
let _gsdtGlobalRoot; // memoized `npm root -g`/@tekyzinc/gsd-t
|
|
31
|
+
|
|
32
|
+
function gsdtGlobalNodeModules() {
|
|
33
|
+
if (_gsdtGlobalRoot !== undefined) return _gsdtGlobalRoot;
|
|
34
|
+
try {
|
|
35
|
+
const groot = execSync('npm root -g', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
36
|
+
_gsdtGlobalRoot = path.join(groot, '@tekyzinc', 'gsd-t', 'node_modules');
|
|
37
|
+
} catch {
|
|
38
|
+
_gsdtGlobalRoot = null;
|
|
39
|
+
}
|
|
40
|
+
return _gsdtGlobalRoot;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resolve and require a native graph dependency from any known location.
|
|
45
|
+
* @param {string} moduleName e.g. 'better-sqlite3', 'tree-sitter'
|
|
46
|
+
* @returns {*} the required module
|
|
47
|
+
* @throws {Error} a clear, actionable error if it cannot be found anywhere
|
|
48
|
+
*/
|
|
49
|
+
function requireGraphDep(moduleName) {
|
|
50
|
+
if (_cache.has(moduleName)) return _cache.get(moduleName);
|
|
51
|
+
|
|
52
|
+
const tried = [];
|
|
53
|
+
|
|
54
|
+
// 1. Normal resolution (this file's own module graph).
|
|
55
|
+
try {
|
|
56
|
+
const m = require(moduleName);
|
|
57
|
+
_cache.set(moduleName, m);
|
|
58
|
+
return m;
|
|
59
|
+
} catch { tried.push('local module graph'); }
|
|
60
|
+
|
|
61
|
+
// 2–4. Explicit candidate directories.
|
|
62
|
+
const candidates = [
|
|
63
|
+
path.join(process.cwd(), 'node_modules', moduleName), // 2. project
|
|
64
|
+
gsdtGlobalNodeModules() ? path.join(gsdtGlobalNodeModules(), moduleName) : null, // 3. global pkg
|
|
65
|
+
path.join(__dirname, '..', 'node_modules', moduleName), // 4. GSD-T dev tree
|
|
66
|
+
].filter(Boolean);
|
|
67
|
+
|
|
68
|
+
for (const c of candidates) {
|
|
69
|
+
tried.push(c);
|
|
70
|
+
try {
|
|
71
|
+
const m = require(c);
|
|
72
|
+
_cache.set(moduleName, m);
|
|
73
|
+
return m;
|
|
74
|
+
} catch { /* try next */ }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
throw new Error(
|
|
78
|
+
`graph dependency '${moduleName}' unavailable — the code graph cannot run. ` +
|
|
79
|
+
'Reinstall GSD-T (npx @tekyzinc/gsd-t install) so the native graph deps are present. ' +
|
|
80
|
+
`Searched: ${tried.join(' | ')}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Back-compat convenience for the store engine. */
|
|
85
|
+
function requireBetterSqlite() {
|
|
86
|
+
return requireGraphDep('better-sqlite3');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { requireGraphDep, requireBetterSqlite };
|
package/bin/gsd-t.js
CHANGED
|
@@ -2682,6 +2682,10 @@ const PROJECT_BIN_TOOLS = [
|
|
|
2682
2682
|
// [[project_code_graph_universal_consumer]] [[feedback_graph_is_architectural_anchor]]
|
|
2683
2683
|
"gsd-t-graph-query-cli.cjs", "gsd-t-graph-index.cjs", "gsd-t-graph-freshness.cjs",
|
|
2684
2684
|
"gsd-t-graph-edge-extract.cjs", "gsd-t-graph-scip-upgrade.cjs", "gsd-t-scip-reader.cjs",
|
|
2685
|
+
// M96 — multi-location resolver for the store engine (better-sqlite3), so a
|
|
2686
|
+
// copied tool finds the engine from the GSD-T global package, not the project's
|
|
2687
|
+
// own (usually absent) node_modules. Fail-loud with remediation if all miss.
|
|
2688
|
+
"gsd-t-require-store.cjs",
|
|
2685
2689
|
];
|
|
2686
2690
|
|
|
2687
2691
|
// Files that older versions of this installer copied into project bin/ but
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.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",
|
|
@@ -31,12 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@playwright/test": "^1.55.0",
|
|
34
|
-
"better-sqlite3": "^12.11.1",
|
|
35
34
|
"graphology": "^0.26.0",
|
|
36
|
-
"kuzu": "^0.11.3"
|
|
37
|
-
"tree-sitter": "^0.21.1",
|
|
38
|
-
"tree-sitter-python": "^0.21.0",
|
|
39
|
-
"tree-sitter-typescript": "^0.23.2"
|
|
35
|
+
"kuzu": "^0.11.3"
|
|
40
36
|
},
|
|
41
37
|
"files": [
|
|
42
38
|
"bin/",
|
|
@@ -49,5 +45,11 @@
|
|
|
49
45
|
],
|
|
50
46
|
"engines": {
|
|
51
47
|
"node": ">=16.0.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"better-sqlite3": "^12.11.1",
|
|
51
|
+
"tree-sitter": "^0.21.1",
|
|
52
|
+
"tree-sitter-typescript": "^0.23.2",
|
|
53
|
+
"tree-sitter-python": "^0.21.0"
|
|
52
54
|
}
|
|
53
55
|
}
|