@tekyzinc/gsd-t 4.9.14 → 4.10.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 (52) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/bin/gsd-t-competition-judge.cjs +7 -1
  4. package/bin/gsd-t-context-brief-kinds/impact.cjs +91 -4
  5. package/bin/gsd-t-context-brief-kinds/partition.cjs +95 -0
  6. package/bin/gsd-t-context-brief-kinds/plan.cjs +110 -4
  7. package/bin/gsd-t-file-disjointness.cjs +319 -7
  8. package/bin/gsd-t-graph-anti-grep-lint.cjs +515 -0
  9. package/bin/gsd-t-graph-edge-extract.cjs +622 -0
  10. package/bin/gsd-t-graph-freshness.cjs +506 -0
  11. package/bin/gsd-t-graph-index.cjs +540 -0
  12. package/bin/gsd-t-graph-k1-sqlite-stream.cjs +251 -0
  13. package/bin/gsd-t-graph-query-cli.cjs +1182 -0
  14. package/bin/gsd-t-graph-scip-upgrade.cjs +440 -0
  15. package/bin/gsd-t-graph-store-bakeoff.cjs +889 -0
  16. package/bin/gsd-t-graph-synthetic-gen.cjs +304 -0
  17. package/bin/gsd-t-graph-ts-throughput.cjs +587 -0
  18. package/bin/gsd-t-require-store.cjs +89 -0
  19. package/bin/gsd-t-scip-reader.cjs +167 -0
  20. package/bin/gsd-t.js +170 -48
  21. package/commands/gsd-t-debug.md +10 -0
  22. package/commands/gsd-t-design-build.md +10 -0
  23. package/commands/gsd-t-execute.md +15 -0
  24. package/commands/gsd-t-feature.md +15 -7
  25. package/commands/gsd-t-gap-analysis.md +17 -7
  26. package/commands/gsd-t-impact.md +25 -0
  27. package/commands/gsd-t-integrate.md +25 -0
  28. package/commands/gsd-t-partition.md +18 -0
  29. package/commands/gsd-t-plan.md +16 -0
  30. package/commands/gsd-t-populate.md +16 -5
  31. package/commands/gsd-t-prd.md +18 -0
  32. package/commands/gsd-t-project.md +19 -0
  33. package/commands/gsd-t-promote-debt.md +16 -5
  34. package/commands/gsd-t-qa.md +20 -8
  35. package/commands/gsd-t-quick.md +10 -0
  36. package/commands/gsd-t-scan.md +21 -3
  37. package/commands/gsd-t-test-sync.md +10 -0
  38. package/commands/gsd-t-verify.md +25 -0
  39. package/commands/gsd-t-wave.md +8 -0
  40. package/package.json +12 -2
  41. package/templates/workflows/gsd-t-debug.workflow.js +81 -0
  42. package/templates/workflows/gsd-t-integrate.workflow.js +47 -1
  43. package/templates/workflows/gsd-t-phase.workflow.js +84 -0
  44. package/templates/workflows/gsd-t-quick.workflow.js +64 -0
  45. package/templates/workflows/gsd-t-scan.workflow.js +200 -9
  46. package/templates/workflows/gsd-t-verify.workflow.js +50 -1
  47. package/bin/graph-cgc.js +0 -510
  48. package/bin/graph-indexer.js +0 -147
  49. package/bin/graph-overlay.js +0 -195
  50. package/bin/graph-parsers.js +0 -327
  51. package/bin/graph-query.js +0 -453
  52. package/bin/graph-store.js +0 -154
@@ -1,453 +0,0 @@
1
- 'use strict';
2
- const store = require('./graph-store');
3
- const { indexProject } = require('./graph-indexer');
4
- const { cgcProvider, cgcQuery } = require('./graph-cgc');
5
-
6
- /**
7
- * Graph Abstraction Layer — unified query interface.
8
- * Routes queries to best available provider: CGC → native → grep.
9
- * Commands call query() and never interact with providers directly.
10
- */
11
-
12
- const providers = [];
13
- let sessionProvider = null; // cached per session
14
- let _lastFreshnessCheck = 0; // timestamp of last staleness check
15
-
16
- function registerProvider(provider) {
17
- providers.push(provider);
18
- providers.sort((a, b) => a.priority - b.priority);
19
- }
20
-
21
- function getProviders() {
22
- return [...providers];
23
- }
24
-
25
- function selectProvider() {
26
- if (sessionProvider) return sessionProvider;
27
- for (const p of providers) {
28
- if (p.available()) {
29
- sessionProvider = p;
30
- return p;
31
- }
32
- }
33
- return null;
34
- }
35
-
36
- function resetSession() {
37
- sessionProvider = null;
38
- _lastFreshnessCheck = 0;
39
- }
40
-
41
- // --- Native provider ---
42
-
43
- function nativeAvailable(projectRoot) {
44
- const meta = store.readMeta(projectRoot);
45
- return meta !== null && meta.entityCount > 0;
46
- }
47
-
48
- function nativeQuery(type, params, projectRoot) {
49
- const idx = store.readIndex(projectRoot);
50
- const calls = store.readCalls(projectRoot);
51
- const imps = store.readImports(projectRoot);
52
- const contracts = store.readContracts(projectRoot);
53
- const requirements = store.readRequirements(projectRoot);
54
- const tests = store.readTests(projectRoot);
55
- const surfaces = store.readSurfaces(projectRoot);
56
-
57
- switch (type) {
58
- case 'getEntity': {
59
- return idx.entities.find(e =>
60
- e.name === params.name &&
61
- (!params.file || e.file === params.file)
62
- ) || null;
63
- }
64
-
65
- case 'getEntities': {
66
- return idx.entities.filter(e => e.file === params.file);
67
- }
68
-
69
- case 'getEntitiesByDomain': {
70
- return idx.entities.filter(
71
- e => e.domain === params.domain
72
- );
73
- }
74
-
75
- case 'getCallers': {
76
- const edges = calls.edges.filter(
77
- e => e.callee === params.entity ||
78
- e.callee.endsWith(':' + params.entity)
79
- );
80
- return edges.map(e => {
81
- const caller = idx.entities.find(
82
- ent => ent.id === e.caller
83
- );
84
- return caller || { id: e.caller, name: e.caller };
85
- });
86
- }
87
-
88
- case 'getCallees': {
89
- const edges = calls.edges.filter(
90
- e => e.caller === params.entity ||
91
- e.caller.endsWith(':' + params.entity)
92
- );
93
- return edges.map(e => {
94
- const callee = idx.entities.find(
95
- ent => ent.id === e.callee
96
- );
97
- return callee || { id: e.callee, name: e.callee };
98
- });
99
- }
100
-
101
- case 'getTransitiveCallers':
102
- case 'getTransitiveCallees': {
103
- // Native: 1-level only (CGC enhances to N-level)
104
- const direction = type === 'getTransitiveCallers'
105
- ? 'getCallers' : 'getCallees';
106
- return nativeQuery(direction, params, projectRoot);
107
- }
108
-
109
- case 'getImports': {
110
- return imps.edges.filter(e => e.source === params.file);
111
- }
112
-
113
- case 'getImporters': {
114
- return imps.edges.filter(e => e.target === params.file ||
115
- e.target.endsWith('/' + params.file));
116
- }
117
-
118
- case 'getDomainOwner': {
119
- const entity = typeof params.entity === 'string'
120
- ? idx.entities.find(e => e.id === params.entity ||
121
- e.name === params.entity)
122
- : params.entity;
123
- return entity ? entity.domain : null;
124
- }
125
-
126
- case 'getContractFor': {
127
- const m = contracts.mappings.find(
128
- c => c.entity === params.entity ||
129
- c.entity.endsWith(':' + params.entity)
130
- );
131
- return m ? m.contract : null;
132
- }
133
-
134
- case 'getRequirementFor': {
135
- const m = requirements.mappings.find(
136
- r => r.entity === params.entity ||
137
- r.entity.endsWith(':' + params.entity)
138
- );
139
- return m ? m.requirement : null;
140
- }
141
-
142
- case 'getTestsFor': {
143
- return tests.mappings.filter(
144
- t => t.entity === params.entity ||
145
- t.entity.endsWith(':' + params.entity)
146
- );
147
- }
148
-
149
- case 'getDebtFor': {
150
- return []; // debt mapping is basic
151
- }
152
-
153
- case 'getSurfaceConsumers': {
154
- const m = surfaces.mappings.find(
155
- s => s.entity === params.entity ||
156
- s.entity.endsWith(':' + params.entity)
157
- );
158
- return m ? m.surfaces : [];
159
- }
160
-
161
- case 'findDuplicates': {
162
- // Native: name-based only (CGC adds AST comparison)
163
- const names = {};
164
- for (const e of idx.entities) {
165
- if (!names[e.name]) names[e.name] = [];
166
- names[e.name].push(e);
167
- }
168
- const dupes = [];
169
- for (const [name, ents] of Object.entries(names)) {
170
- if (ents.length > 1) {
171
- for (let i = 0; i < ents.length - 1; i++) {
172
- dupes.push({
173
- entityA: ents[i],
174
- entityB: ents[i + 1],
175
- similarity: 1.0
176
- });
177
- }
178
- }
179
- }
180
- return dupes;
181
- }
182
-
183
- case 'findDeadCode': {
184
- // Entities that are not called and not exported
185
- const calledIds = new Set(
186
- calls.edges.map(e => e.callee)
187
- );
188
- return idx.entities.filter(e =>
189
- !e.exported && !calledIds.has(e.id)
190
- );
191
- }
192
-
193
- case 'findCircularDeps': {
194
- // Native: import-level cycle detection
195
- const graph = {};
196
- for (const edge of imps.edges) {
197
- if (!graph[edge.source]) graph[edge.source] = [];
198
- graph[edge.source].push(edge.target);
199
- }
200
- const cycles = [];
201
- const visited = new Set();
202
- const stack = new Set();
203
-
204
- function dfs(node, pathArr) {
205
- if (stack.has(node)) {
206
- const cycleStart = pathArr.indexOf(node);
207
- if (cycleStart >= 0) {
208
- cycles.push({
209
- path: pathArr.slice(cycleStart),
210
- entities: []
211
- });
212
- }
213
- return;
214
- }
215
- if (visited.has(node)) return;
216
- visited.add(node);
217
- stack.add(node);
218
- pathArr.push(node);
219
- for (const neighbor of (graph[node] || [])) {
220
- dfs(neighbor, [...pathArr]);
221
- }
222
- stack.delete(node);
223
- }
224
-
225
- for (const node of Object.keys(graph)) {
226
- dfs(node, []);
227
- }
228
- return cycles;
229
- }
230
-
231
- case 'getDomainBoundaryViolations': {
232
- const violations = [];
233
- for (const edge of calls.edges) {
234
- const callerEnt = idx.entities.find(
235
- e => e.id === edge.caller
236
- );
237
- const calleeEnt = idx.entities.find(
238
- e => e.id === edge.callee
239
- );
240
- if (callerEnt && calleeEnt &&
241
- callerEnt.domain && calleeEnt.domain &&
242
- callerEnt.domain !== calleeEnt.domain) {
243
- violations.push({
244
- entity: calleeEnt,
245
- ownerDomain: calleeEnt.domain,
246
- accessedBy: callerEnt,
247
- accessorDomain: callerEnt.domain
248
- });
249
- }
250
- }
251
- return violations;
252
- }
253
-
254
- case 'getProvider': {
255
- const p = selectProvider();
256
- return p ? p.name : 'grep';
257
- }
258
-
259
- case 'getIndexStatus': {
260
- const meta = store.readMeta(projectRoot);
261
- return {
262
- provider: meta ? meta.provider : 'none',
263
- indexed: meta !== null,
264
- entityCount: meta ? meta.entityCount : 0,
265
- lastIndexed: meta ? meta.lastIndexed : null,
266
- stale: false,
267
- stalePaths: []
268
- };
269
- }
270
-
271
- case 'reindex': {
272
- return indexProject(projectRoot, {
273
- force: params.force || false
274
- });
275
- }
276
-
277
- default:
278
- return null;
279
- }
280
- }
281
-
282
- const nativeProvider = {
283
- name: 'native',
284
- priority: 2,
285
- _projectRoot: null,
286
- setProjectRoot(root) { this._projectRoot = root; },
287
- available() {
288
- return this._projectRoot
289
- ? nativeAvailable(this._projectRoot) : false;
290
- },
291
- query(type, params) {
292
- return nativeQuery(type, params, this._projectRoot);
293
- }
294
- };
295
-
296
- // --- Grep fallback provider ---
297
-
298
- const fs = require('fs');
299
- const path = require('path');
300
- const { execFileSync } = require('child_process');
301
-
302
- const SAFE_ENTITY_RE = /^[\w.\-/\\:]+$/;
303
-
304
- function grepQuery(type, params, projectRoot) {
305
- switch (type) {
306
- case 'getCallers': {
307
- const name = params.entity;
308
- if (!name || !SAFE_ENTITY_RE.test(name)) return [];
309
- try {
310
- const out = execFileSync('grep', ['-rn', name + '(', '--include=*.js', '--include=*.ts', '--include=*.py', projectRoot], { encoding: 'utf8', timeout: 5000 });
311
- return out.split('\n').filter(Boolean).map(line => {
312
- const [file] = line.split(':');
313
- return {
314
- id: file,
315
- name: 'grep_result',
316
- file: path.relative(projectRoot, file)
317
- };
318
- });
319
- } catch { return []; }
320
- }
321
-
322
- case 'getImporters': {
323
- const name = params.file || params.entity;
324
- if (!name || !SAFE_ENTITY_RE.test(name)) return [];
325
- try {
326
- const out = execFileSync('grep', ['-rn', '-e', 'import.*' + name, '-e', 'require.*' + name, '--include=*.js', '--include=*.ts', projectRoot], { encoding: 'utf8', timeout: 5000 });
327
- return out.split('\n').filter(Boolean).map(line => ({
328
- source: line.split(':')[0],
329
- target: name,
330
- names: [],
331
- line: parseInt(line.split(':')[1]) || 0
332
- }));
333
- } catch { return []; }
334
- }
335
-
336
- case 'getProvider':
337
- return 'grep';
338
-
339
- case 'getIndexStatus':
340
- return {
341
- provider: 'grep',
342
- indexed: false,
343
- entityCount: 0,
344
- lastIndexed: null,
345
- stale: true,
346
- stalePaths: []
347
- };
348
-
349
- default:
350
- return null;
351
- }
352
- }
353
-
354
- const grepProvider = {
355
- name: 'grep',
356
- priority: 3,
357
- _projectRoot: null,
358
- setProjectRoot(root) { this._projectRoot = root; },
359
- available() { return true; }, // always available
360
- query(type, params) {
361
- return grepQuery(type, params, this._projectRoot);
362
- }
363
- };
364
-
365
- // --- CGC Sync (Phase 2: keep Neo4j in sync at command boundary) ---
366
-
367
- function _syncCgc(projectRoot) {
368
- if (!cgcProvider.available()) return;
369
- // Use CLI instead of MCP tool call — add_code_to_graph MCP is broken
370
- // on Windows in CGC 0.3.1 (directory param arrives as None)
371
- const { execFileSync } = require('child_process');
372
- const cgcEnv = { ...process.env, PYTHONIOENCODING: 'utf-8' };
373
- const cgcOpts = { timeout: 30000, stdio: ['pipe', 'pipe', 'pipe'], env: cgcEnv };
374
-
375
- // Attempt 1: normal sync
376
- try {
377
- execFileSync('cgc', ['index', projectRoot], cgcOpts);
378
- return;
379
- } catch (err1) {
380
- const msg1 = err1.stderr ? err1.stderr.toString() : err1.message;
381
- // Attempt 2: force re-index to recover from corrupt state
382
- try {
383
- execFileSync('cgc', ['index', projectRoot, '--force'], cgcOpts);
384
- process.stderr.write(
385
- '[GSD-T] CGC sync recovered via force re-index for ' +
386
- projectRoot + '\n'
387
- );
388
- return;
389
- } catch (err2) {
390
- const msg2 = err2.stderr ? err2.stderr.toString() : err2.message;
391
- // Both attempts failed — warn the user clearly
392
- process.stderr.write(
393
- '[GSD-T] ⚠ CGC sync FAILED for ' + projectRoot + '\n' +
394
- ' Error: ' + (msg2 || msg1).split('\n')[0] + '\n' +
395
- ' Impact: Neo4j graph is stale — deep call chain analysis ' +
396
- 'may return outdated results\n' +
397
- ' Fix: run "cgc index ' + projectRoot + ' --force" manually\n'
398
- );
399
- }
400
- }
401
- }
402
-
403
- // --- Main query function ---
404
-
405
- function query(type, params, projectRoot) {
406
- // Set project root on providers
407
- nativeProvider.setProjectRoot(projectRoot);
408
- grepProvider.setProjectRoot(projectRoot);
409
-
410
- // Auto-trigger reindex if stale (command-boundary freshness check)
411
- if (type !== 'reindex' && type !== 'getIndexStatus' &&
412
- type !== 'getProvider') {
413
- const now = Date.now();
414
- if (now - _lastFreshnessCheck > 500) {
415
- _lastFreshnessCheck = now;
416
- const meta = store.readMeta(projectRoot);
417
- if (!meta) {
418
- // No index exists — run initial index
419
- indexProject(projectRoot);
420
- _syncCgc(projectRoot);
421
- } else {
422
- // Check staleness — reindex if any files changed
423
- const result = indexProject(projectRoot);
424
- if (result.filesProcessed > 0) {
425
- _syncCgc(projectRoot);
426
- }
427
- }
428
- }
429
- }
430
-
431
- // Try providers in priority order
432
- for (const p of providers) {
433
- if (!p.available()) continue;
434
- if (p._projectRoot !== undefined) {
435
- p.setProjectRoot(projectRoot);
436
- }
437
- const result = p.query(type, params, projectRoot);
438
- if (result !== null && result !== undefined) return result;
439
- }
440
-
441
- return null;
442
- }
443
-
444
- // Register default providers
445
- registerProvider(cgcProvider);
446
- registerProvider(nativeProvider);
447
- registerProvider(grepProvider);
448
-
449
- module.exports = {
450
- query, registerProvider, getProviders,
451
- selectProvider, resetSession,
452
- nativeProvider, grepProvider
453
- };
@@ -1,154 +0,0 @@
1
- 'use strict';
2
- const fs = require('fs');
3
- const path = require('path');
4
- const crypto = require('crypto');
5
-
6
- const GRAPH_DIR = '.gsd-t/graph';
7
- const FILES = {
8
- index: 'index.json',
9
- calls: 'calls.json',
10
- imports: 'imports.json',
11
- contracts: 'contracts.json',
12
- requirements: 'requirements.json',
13
- tests: 'tests.json',
14
- surfaces: 'surfaces.json',
15
- meta: 'meta.json'
16
- };
17
-
18
- function getGraphDir(projectRoot) {
19
- return path.join(projectRoot, GRAPH_DIR);
20
- }
21
-
22
- function isSymlink(p) {
23
- try { return fs.lstatSync(p).isSymbolicLink(); } catch { return false; }
24
- }
25
-
26
- function ensureDir(projectRoot) {
27
- const dir = getGraphDir(projectRoot);
28
- if (isSymlink(dir)) throw new Error('Graph directory is a symlink: ' + dir);
29
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
30
- return dir;
31
- }
32
-
33
- function readFile(projectRoot, fileName) {
34
- try {
35
- const fp = path.join(getGraphDir(projectRoot), fileName);
36
- if (isSymlink(fp)) return null;
37
- return JSON.parse(fs.readFileSync(fp, 'utf8'));
38
- } catch { return null; }
39
- }
40
-
41
- function writeFile(projectRoot, fileName, data) {
42
- const dir = ensureDir(projectRoot);
43
- const fp = path.join(dir, fileName);
44
- if (isSymlink(fp)) throw new Error('Graph file is a symlink: ' + fp);
45
- fs.writeFileSync(fp, JSON.stringify(data, null, 2), 'utf8');
46
- }
47
-
48
- function readIndex(root) {
49
- return readFile(root, FILES.index) || { entities: [] };
50
- }
51
-
52
- function readCalls(root) {
53
- return readFile(root, FILES.calls) || { edges: [] };
54
- }
55
-
56
- function readImports(root) {
57
- return readFile(root, FILES.imports) || { edges: [] };
58
- }
59
-
60
- function readContracts(root) {
61
- return readFile(root, FILES.contracts) || { mappings: [] };
62
- }
63
-
64
- function readRequirements(root) {
65
- return readFile(root, FILES.requirements) || { mappings: [] };
66
- }
67
-
68
- function readTests(root) {
69
- return readFile(root, FILES.tests) || { mappings: [] };
70
- }
71
-
72
- function readSurfaces(root) {
73
- return readFile(root, FILES.surfaces) || { mappings: [] };
74
- }
75
-
76
- function readMeta(root) {
77
- return readFile(root, FILES.meta);
78
- }
79
-
80
- function writeIndex(root, data) {
81
- writeFile(root, FILES.index, data);
82
- }
83
-
84
- function writeCalls(root, data) {
85
- writeFile(root, FILES.calls, data);
86
- }
87
-
88
- function writeImports(root, data) {
89
- writeFile(root, FILES.imports, data);
90
- }
91
-
92
- function writeContracts(root, data) {
93
- writeFile(root, FILES.contracts, data);
94
- }
95
-
96
- function writeRequirements(root, data) {
97
- writeFile(root, FILES.requirements, data);
98
- }
99
-
100
- function writeTests(root, data) {
101
- writeFile(root, FILES.tests, data);
102
- }
103
-
104
- function writeSurfaces(root, data) {
105
- writeFile(root, FILES.surfaces, data);
106
- }
107
-
108
- function writeMeta(root, data) {
109
- writeFile(root, FILES.meta, data);
110
- }
111
-
112
- function hashContent(content) {
113
- return crypto.createHash('md5').update(content).digest('hex');
114
- }
115
-
116
- function hashFile(filePath) {
117
- try {
118
- const content = fs.readFileSync(filePath, 'utf8');
119
- return hashContent(content);
120
- } catch { return null; }
121
- }
122
-
123
- function isStale(root, sourceFiles) {
124
- const meta = readMeta(root);
125
- if (!meta || !meta.fileHashes) {
126
- return { stale: true, changedFiles: sourceFiles };
127
- }
128
- const changed = [];
129
- for (const f of sourceFiles) {
130
- const hash = hashFile(f);
131
- const rel = path.relative(root, f);
132
- if (hash !== meta.fileHashes[rel]) changed.push(f);
133
- }
134
- return { stale: changed.length > 0, changedFiles: changed };
135
- }
136
-
137
- function clear(root) {
138
- const dir = getGraphDir(root);
139
- if (!fs.existsSync(dir)) return;
140
- for (const name of Object.values(FILES)) {
141
- const fp = path.join(dir, name);
142
- try { fs.unlinkSync(fp); } catch { /* ignore */ }
143
- }
144
- }
145
-
146
- module.exports = {
147
- getGraphDir, ensureDir,
148
- readIndex, readCalls, readImports, readContracts,
149
- readRequirements, readTests, readSurfaces, readMeta,
150
- writeIndex, writeCalls, writeImports, writeContracts,
151
- writeRequirements, writeTests, writeSurfaces, writeMeta,
152
- hashContent, hashFile, isStale, clear,
153
- FILES, GRAPH_DIR
154
- };