@tekyzinc/gsd-t 2.74.12 → 2.76.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +71 -1
  3. package/bin/advisor-integration.js +93 -0
  4. package/bin/check-headless-sessions.js +140 -0
  5. package/bin/context-meter-config.cjs +101 -0
  6. package/bin/context-meter-config.test.cjs +101 -0
  7. package/bin/gsd-t.js +710 -16
  8. package/bin/headless-auto-spawn.js +290 -0
  9. package/bin/model-selector.js +224 -0
  10. package/bin/runway-estimator.js +242 -0
  11. package/bin/token-budget.js +96 -89
  12. package/bin/token-optimizer.js +471 -0
  13. package/bin/token-telemetry.js +246 -0
  14. package/commands/gsd-t-audit.md +3 -3
  15. package/commands/gsd-t-backlog-list.md +38 -0
  16. package/commands/gsd-t-brainstorm.md +3 -3
  17. package/commands/gsd-t-complete-milestone.md +24 -0
  18. package/commands/gsd-t-debug.md +124 -7
  19. package/commands/gsd-t-discuss.md +10 -3
  20. package/commands/gsd-t-doc-ripple.md +32 -4
  21. package/commands/gsd-t-execute.md +107 -52
  22. package/commands/gsd-t-help.md +19 -0
  23. package/commands/gsd-t-integrate.md +67 -4
  24. package/commands/gsd-t-optimization-apply.md +91 -0
  25. package/commands/gsd-t-optimization-reject.md +94 -0
  26. package/commands/gsd-t-partition.md +7 -0
  27. package/commands/gsd-t-pause.md +3 -0
  28. package/commands/gsd-t-plan.md +10 -3
  29. package/commands/gsd-t-prd.md +3 -3
  30. package/commands/gsd-t-quick.md +71 -9
  31. package/commands/gsd-t-reflect.md +3 -7
  32. package/commands/gsd-t-resume.md +36 -0
  33. package/commands/gsd-t-status.md +31 -0
  34. package/commands/gsd-t-test-sync.md +7 -0
  35. package/commands/gsd-t-verify.md +12 -5
  36. package/commands/gsd-t-visualize.md +3 -7
  37. package/commands/gsd-t-wave.md +82 -18
  38. package/docs/GSD-T-README.md +52 -0
  39. package/docs/architecture.md +95 -0
  40. package/docs/infrastructure.md +117 -0
  41. package/docs/methodology.md +36 -0
  42. package/docs/prd-harness-evolution.md +51 -37
  43. package/docs/requirements.md +66 -0
  44. package/package.json +1 -1
  45. package/scripts/context-meter/count-tokens-client.js +221 -0
  46. package/scripts/context-meter/count-tokens-client.test.js +308 -0
  47. package/scripts/context-meter/test-injector.js +55 -0
  48. package/scripts/context-meter/threshold.js +88 -0
  49. package/scripts/context-meter/threshold.test.js +255 -0
  50. package/scripts/context-meter/transcript-parser.js +252 -0
  51. package/scripts/context-meter/transcript-parser.test.js +320 -0
  52. package/scripts/gsd-t-context-meter.e2e.test.js +415 -0
  53. package/scripts/gsd-t-context-meter.js +350 -0
  54. package/scripts/gsd-t-context-meter.test.js +417 -0
  55. package/scripts/gsd-t-heartbeat.js +2 -2
  56. package/scripts/gsd-t-statusline.js +23 -8
  57. package/templates/CLAUDE-global.md +5 -1
  58. package/templates/CLAUDE-project.md +26 -6
  59. package/templates/context-meter-config.json +10 -0
  60. package/templates/prompts/README.md +1 -1
  61. package/bin/task-counter.cjs +0 -161
@@ -0,0 +1,101 @@
1
+ const { test } = require("node:test");
2
+ const assert = require("node:assert/strict");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const os = require("os");
6
+
7
+ const { loadConfig, DEFAULTS } = require("./context-meter-config.cjs");
8
+
9
+ function makeProject(config) {
10
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "cmcfg-"));
11
+ fs.mkdirSync(path.join(root, ".gsd-t"), { recursive: true });
12
+ if (config !== undefined) {
13
+ fs.writeFileSync(
14
+ path.join(root, ".gsd-t", "context-meter-config.json"),
15
+ typeof config === "string" ? config : JSON.stringify(config)
16
+ );
17
+ }
18
+ return root;
19
+ }
20
+
21
+ test("missing config file → returns defaults", () => {
22
+ const root = makeProject();
23
+ assert.deepEqual(loadConfig(root), DEFAULTS);
24
+ });
25
+
26
+ test("valid full config → returns exact values", () => {
27
+ const custom = {
28
+ version: 1,
29
+ thresholdPct: 80,
30
+ modelWindowSize: 400000,
31
+ checkFrequency: 10,
32
+ apiKeyEnvVar: "CLAUDE_KEY",
33
+ statePath: ".gsd-t/my-state.json",
34
+ logPath: ".gsd-t/my.log",
35
+ timeoutMs: 5000,
36
+ };
37
+ const root = makeProject(custom);
38
+ assert.deepEqual(loadConfig(root), custom);
39
+ });
40
+
41
+ test("partial config → missing fields filled with defaults", () => {
42
+ const root = makeProject({ thresholdPct: 60, timeoutMs: 1000 });
43
+ const cfg = loadConfig(root);
44
+ assert.equal(cfg.thresholdPct, 60);
45
+ assert.equal(cfg.timeoutMs, 1000);
46
+ assert.equal(cfg.modelWindowSize, DEFAULTS.modelWindowSize);
47
+ assert.equal(cfg.checkFrequency, DEFAULTS.checkFrequency);
48
+ assert.equal(cfg.apiKeyEnvVar, DEFAULTS.apiKeyEnvVar);
49
+ });
50
+
51
+ test("thresholdPct out of range throws", () => {
52
+ for (const bad of [0, 100, -5, 150, "80"]) {
53
+ const root = makeProject({ thresholdPct: bad });
54
+ assert.throws(() => loadConfig(root), /thresholdPct/);
55
+ }
56
+ });
57
+
58
+ test("modelWindowSize <= 0 throws", () => {
59
+ for (const bad of [0, -1, 1.5, "100"]) {
60
+ const root = makeProject({ modelWindowSize: bad });
61
+ assert.throws(() => loadConfig(root), /modelWindowSize/);
62
+ }
63
+ });
64
+
65
+ test("checkFrequency < 1 throws", () => {
66
+ for (const bad of [0, -1, 0.5]) {
67
+ const root = makeProject({ checkFrequency: bad });
68
+ assert.throws(() => loadConfig(root), /checkFrequency/);
69
+ }
70
+ });
71
+
72
+ test("empty apiKeyEnvVar throws", () => {
73
+ const root = makeProject({ apiKeyEnvVar: "" });
74
+ assert.throws(() => loadConfig(root), /apiKeyEnvVar/);
75
+ });
76
+
77
+ test("unknown version throws with migration pointer", () => {
78
+ const root = makeProject({ version: 2, thresholdPct: 75 });
79
+ assert.throws(() => loadConfig(root), /version 2|migration/i);
80
+ });
81
+
82
+ test("config containing an apiKey field is rejected as leak", () => {
83
+ const root = makeProject({ apiKey: "sk-ant-abc123" });
84
+ assert.throws(() => loadConfig(root), /api.?key/i);
85
+ });
86
+
87
+ test("config containing a long hex-like string value is rejected as leak", () => {
88
+ const longHex = "a".repeat(120);
89
+ const root = makeProject({ customField: longHex });
90
+ assert.throws(() => loadConfig(root), /api.?key|token-like/i);
91
+ });
92
+
93
+ test("invalid JSON throws with clear message", () => {
94
+ const root = makeProject("{ not valid json");
95
+ assert.throws(() => loadConfig(root), /invalid JSON/);
96
+ });
97
+
98
+ test("non-object JSON throws", () => {
99
+ const root = makeProject("[1, 2, 3]");
100
+ assert.throws(() => loadConfig(root), /JSON object/);
101
+ });