@tekyzinc/gsd-t 5.8.10 → 5.10.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 +57 -0
- package/README.md +1 -1
- package/bin/gsd-t-concise-rewrite.cjs +223 -0
- package/bin/gsd-t-fallback-detect.cjs +624 -0
- package/bin/gsd-t-install-check.cjs +342 -0
- package/bin/gsd-t-project-history.cjs +374 -0
- package/bin/gsd-t-rule-mine.cjs +467 -0
- package/bin/gsd-t-verify-gate.cjs +2 -0
- package/bin/gsd-t.js +199 -5
- package/commands/gsd-t-setup.md +98 -74
- package/package.json +1 -1
- package/scripts/gsd-t-concise-hook.js +200 -0
- package/scripts/gsd-t-fallback-guard.js +237 -0
- package/scripts/gsd-t-install-heal.js +183 -0
- package/templates/CLAUDE-project.md +50 -107
package/bin/gsd-t.js
CHANGED
|
@@ -505,6 +505,31 @@ const WORKTREE_HOOK_MARKER = "gsd-t-worktree-guard";
|
|
|
505
505
|
const WORKTREE_HOOK_COMMAND =
|
|
506
506
|
'bash -c \'[ -f "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-worktree-guard.js" ] && node "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-worktree-guard.js" || true\'';
|
|
507
507
|
|
|
508
|
+
// ─── M106 Fallback guard (PreToolUse Write|Edit) ────────────────────────────
|
|
509
|
+
// Denies a write that introduces a fallback the user never approved. NO `|| true`
|
|
510
|
+
// here, unlike the worktree guard: if this script is missing, the shell must fail
|
|
511
|
+
// loudly rather than let unchecked writes through. Swallowing its absence is the
|
|
512
|
+
// exact pattern the guard exists to stop.
|
|
513
|
+
const FALLBACK_HOOK_MARKER = "gsd-t-fallback-guard";
|
|
514
|
+
const FALLBACK_HOOK_COMMAND =
|
|
515
|
+
'node "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-fallback-guard.js"';
|
|
516
|
+
|
|
517
|
+
// ─── M108 Install self-heal (SessionStart) ──────────────────────────────────
|
|
518
|
+
// Checks the project's tools before any work starts, restores what is missing,
|
|
519
|
+
// and reports what it could not fix. Not a fallback — it repairs the failure
|
|
520
|
+
// and then the session runs correctly, rather than routing around it.
|
|
521
|
+
const INSTALL_HEAL_MARKER = "gsd-t-install-heal";
|
|
522
|
+
const INSTALL_HEAL_COMMAND =
|
|
523
|
+
'bash -c \'[ -f "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-install-heal.js" ] && node "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-install-heal.js" || true\'';
|
|
524
|
+
|
|
525
|
+
// ─── M107 Concise hook (Stop) ───────────────────────────────────────────────
|
|
526
|
+
// Sends a long reply to a fresh Claude for a shorter rewrite. Fail-open by
|
|
527
|
+
// design (`|| true`): it governs how a reply READS, never whether it is true,
|
|
528
|
+
// so a broken rewriter must never gag a correct answer.
|
|
529
|
+
const CONCISE_HOOK_MARKER = "gsd-t-concise-hook";
|
|
530
|
+
const CONCISE_HOOK_COMMAND =
|
|
531
|
+
'bash -c \'[ -f "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-concise-hook.js" ] && node "$(npm root -g)/@tekyzinc/gsd-t/scripts/gsd-t-concise-hook.js" || true\'';
|
|
532
|
+
|
|
508
533
|
// Append entries to {projectDir}/.gitignore. Each entry added only if absent.
|
|
509
534
|
// Idempotent. Returns true if any entries were added, false otherwise.
|
|
510
535
|
function ensureGitignoreEntries(projectDir, entries) {
|
|
@@ -963,6 +988,76 @@ function configureWorktreeGuardHook(settingsPath) {
|
|
|
963
988
|
return configureWriteEditHook(settingsPath, WORKTREE_HOOK_MARKER, WORKTREE_HOOK_COMMAND, "worktree guard");
|
|
964
989
|
}
|
|
965
990
|
|
|
991
|
+
// M106 — register the fallback guard on Write|Edit. Same registrar again.
|
|
992
|
+
function configureFallbackGuardHook(settingsPath) {
|
|
993
|
+
return configureWriteEditHook(settingsPath, FALLBACK_HOOK_MARKER, FALLBACK_HOOK_COMMAND, "fallback guard");
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// M107 — register the concise rewriter on Stop. Not a Write|Edit hook, so it
|
|
997
|
+
// uses the Stop registrar below rather than configureWriteEditHook.
|
|
998
|
+
function configureConciseHook(settingsPath) {
|
|
999
|
+
return configureStopHook(settingsPath, CONCISE_HOOK_MARKER, CONCISE_HOOK_COMMAND, "concise rewrite");
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// M108 — register the install self-heal on SessionStart, so a broken install is
|
|
1003
|
+
// repaired before any work begins.
|
|
1004
|
+
function configureInstallHealHook(settingsPath) {
|
|
1005
|
+
return configureEventHook(settingsPath, "SessionStart", INSTALL_HEAL_MARKER, INSTALL_HEAL_COMMAND, "install self-heal");
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Register a Stop hook by marker. Mirrors configureWriteEditHook exactly, on the
|
|
1009
|
+
// Stop event instead of PreToolUse.
|
|
1010
|
+
function configureStopHook(settingsPath, marker, command, label) {
|
|
1011
|
+
return configureEventHook(settingsPath, "Stop", marker, command, label);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Register a hook on any event by marker. One registrar for every event, so a
|
|
1015
|
+
// new hook needs no new copy of this logic.
|
|
1016
|
+
function configureEventHook(settingsPath, event, marker, command, label) {
|
|
1017
|
+
const targetPath = settingsPath || SETTINGS_JSON;
|
|
1018
|
+
let settings = {};
|
|
1019
|
+
if (fs.existsSync(targetPath)) {
|
|
1020
|
+
try {
|
|
1021
|
+
settings = JSON.parse(fs.readFileSync(targetPath, "utf8"));
|
|
1022
|
+
if (!settings || typeof settings !== "object") settings = {};
|
|
1023
|
+
} catch {
|
|
1024
|
+
warn(`settings.json has invalid JSON — cannot configure ${label} hook`);
|
|
1025
|
+
return { installed: false, action: "noop" };
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if (!settings.hooks) settings.hooks = {};
|
|
1029
|
+
if (!Array.isArray(settings.hooks[event])) settings.hooks[event] = [];
|
|
1030
|
+
|
|
1031
|
+
let action = "noop";
|
|
1032
|
+
let found = false;
|
|
1033
|
+
for (const entry of settings.hooks[event]) {
|
|
1034
|
+
if (!entry || !Array.isArray(entry.hooks)) continue;
|
|
1035
|
+
for (const h of entry.hooks) {
|
|
1036
|
+
if (h && typeof h.command === "string" && h.command.includes(marker)) {
|
|
1037
|
+
found = true;
|
|
1038
|
+
if (h.command !== command) { h.command = command; action = "refreshed"; }
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (!found) {
|
|
1043
|
+
// The install check goes FIRST on SessionStart, so a broken install is
|
|
1044
|
+
// repaired before anything else tries to use the missing tools.
|
|
1045
|
+
const entry = { matcher: "", hooks: [{ type: "command", command }] };
|
|
1046
|
+
if (event === "SessionStart") settings.hooks[event].unshift(entry);
|
|
1047
|
+
else settings.hooks[event].push(entry);
|
|
1048
|
+
action = "added";
|
|
1049
|
+
}
|
|
1050
|
+
if (action === "noop") return { installed: true, action };
|
|
1051
|
+
|
|
1052
|
+
try {
|
|
1053
|
+
fs.writeFileSync(targetPath, JSON.stringify(settings, null, 2));
|
|
1054
|
+
} catch (e) {
|
|
1055
|
+
warn(`Failed to write settings.json: ${e.message}`);
|
|
1056
|
+
return { installed: false, action: "noop" };
|
|
1057
|
+
}
|
|
1058
|
+
return { installed: true, action };
|
|
1059
|
+
}
|
|
1060
|
+
|
|
966
1061
|
function configureWriteEditHook(settingsPath, marker, command, label) {
|
|
967
1062
|
const targetPath = settingsPath || SETTINGS_JSON;
|
|
968
1063
|
let settings = {};
|
|
@@ -1533,10 +1628,16 @@ const UTILITY_SCRIPTS = ["gsd-t-tools.js", "gsd-t-statusline.js", "gsd-t-event-w
|
|
|
1533
1628
|
|
|
1534
1629
|
function installUtilityScripts() {
|
|
1535
1630
|
ensureDir(SCRIPTS_DIR);
|
|
1631
|
+
const notDelivered = [];
|
|
1536
1632
|
for (const script of UTILITY_SCRIPTS) {
|
|
1537
1633
|
const src = path.join(PKG_SCRIPTS, script);
|
|
1538
1634
|
const dest = path.join(SCRIPTS_DIR, script);
|
|
1539
|
-
if (!fs.existsSync(src))
|
|
1635
|
+
if (!fs.existsSync(src)) {
|
|
1636
|
+
// Promised but absent from the package. Reported, never skipped quietly —
|
|
1637
|
+
// the same silence let projects run for weeks on a half install.
|
|
1638
|
+
notDelivered.push(script);
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1540
1641
|
const srcContent = fs.readFileSync(src, "utf8");
|
|
1541
1642
|
const destContent = fs.existsSync(dest) ? fs.readFileSync(dest, "utf8") : "";
|
|
1542
1643
|
if (normalizeEol(srcContent) !== normalizeEol(destContent)) {
|
|
@@ -1545,6 +1646,11 @@ function installUtilityScripts() {
|
|
|
1545
1646
|
info(`${script} unchanged`);
|
|
1546
1647
|
}
|
|
1547
1648
|
}
|
|
1649
|
+
if (notDelivered.length) {
|
|
1650
|
+
warn(`${notDelivered.length} script(s) are named by the installer but absent from the package:`);
|
|
1651
|
+
for (const s of notDelivered) warn(` ${s}`);
|
|
1652
|
+
warn(` Anything depending on these will fail. This is a packaging defect.`);
|
|
1653
|
+
}
|
|
1548
1654
|
}
|
|
1549
1655
|
|
|
1550
1656
|
// ─── Global Bin Tools (~/.claude/bin/) ───────────────────────────────────────
|
|
@@ -1591,6 +1697,21 @@ const GLOBAL_BIN_TOOLS = [
|
|
|
1591
1697
|
// caller but absent from BOTH lists is dead in every project
|
|
1592
1698
|
// ([[project_global_bin_propagation_gap]], 4 prior occurrences).
|
|
1593
1699
|
"gsd-t-pseudocode-style.cjs",
|
|
1700
|
+
// M106 — Fallback detector. scripts/gsd-t-fallback-guard.js (a PreToolUse hook)
|
|
1701
|
+
// shells out to this by absolute path; if it is missing the guard DENIES the
|
|
1702
|
+
// write rather than allowing it unchecked, so an omission here breaks every
|
|
1703
|
+
// Write/Edit rather than failing silently. Also in PROJECT_BIN_TOOLS below.
|
|
1704
|
+
"gsd-t-fallback-detect.cjs",
|
|
1705
|
+
// M107 — Concise rewriter. scripts/gsd-t-concise-hook.js (a Stop hook) shells
|
|
1706
|
+
// out to this; absent, the hook allows the long reply through (fail-open by
|
|
1707
|
+
// design — it governs readability, never truth).
|
|
1708
|
+
"gsd-t-concise-rewrite.cjs",
|
|
1709
|
+
// M108 — Install self-check, run by the SessionStart hook and by
|
|
1710
|
+
// `gsd-t install-check`.
|
|
1711
|
+
"gsd-t-install-check.cjs",
|
|
1712
|
+
// M109 — project-history reader + rule miner, used by /gsd-t-setup to write a
|
|
1713
|
+
// project CLAUDE.md from what actually happened rather than from a template.
|
|
1714
|
+
"gsd-t-project-history.cjs", "gsd-t-rule-mine.cjs",
|
|
1594
1715
|
];
|
|
1595
1716
|
|
|
1596
1717
|
function installGlobalBinTools() {
|
|
@@ -1838,10 +1959,14 @@ const SHARED_TEMPLATES = [
|
|
|
1838
1959
|
function installSharedTemplates() {
|
|
1839
1960
|
ensureDir(CLAUDE_TEMPLATES_DIR);
|
|
1840
1961
|
let installed = 0, skipped = 0;
|
|
1962
|
+
const notDelivered = [];
|
|
1841
1963
|
for (const file of SHARED_TEMPLATES) {
|
|
1842
1964
|
const src = path.join(PKG_TEMPLATES, file);
|
|
1843
1965
|
const dest = path.join(CLAUDE_TEMPLATES_DIR, file);
|
|
1844
|
-
if (!fs.existsSync(src))
|
|
1966
|
+
if (!fs.existsSync(src)) {
|
|
1967
|
+
notDelivered.push(file); // promised but absent — reported, never silent
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1845
1970
|
if (fs.existsSync(dest) &&
|
|
1846
1971
|
normalizeEol(fs.readFileSync(src, "utf8")) === normalizeEol(fs.readFileSync(dest, "utf8"))) {
|
|
1847
1972
|
skipped++;
|
|
@@ -1852,6 +1977,10 @@ function installSharedTemplates() {
|
|
|
1852
1977
|
}
|
|
1853
1978
|
if (skipped > 0) info(`${skipped} templates unchanged`);
|
|
1854
1979
|
success(`${installed + skipped} shared templates → ~/.claude/templates/`);
|
|
1980
|
+
if (notDelivered.length) {
|
|
1981
|
+
warn(`${notDelivered.length} template(s) are named by the installer but absent from the package:`);
|
|
1982
|
+
for (const f of notDelivered) warn(` ${f}`);
|
|
1983
|
+
}
|
|
1855
1984
|
}
|
|
1856
1985
|
|
|
1857
1986
|
function installCommands(isUpdate) {
|
|
@@ -2035,6 +2164,27 @@ async function doInstall(opts = {}) {
|
|
|
2035
2164
|
else info("Worktree-collision guard already configured");
|
|
2036
2165
|
}
|
|
2037
2166
|
|
|
2167
|
+
const fbHook = configureFallbackGuardHook(SETTINGS_JSON);
|
|
2168
|
+
if (fbHook.installed) {
|
|
2169
|
+
if (fbHook.action === "added") success("Fallback guard added (denies a write that adds an unapproved fallback — M106)");
|
|
2170
|
+
else if (fbHook.action === "refreshed") success("Fallback guard refreshed");
|
|
2171
|
+
else info("Fallback guard already configured");
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
const ccHook = configureConciseHook(SETTINGS_JSON);
|
|
2175
|
+
if (ccHook.installed) {
|
|
2176
|
+
if (ccHook.action === "added") success("Concise-rewrite hook added (shortens a long reply before you read it — M107)");
|
|
2177
|
+
else if (ccHook.action === "refreshed") success("Concise-rewrite hook refreshed");
|
|
2178
|
+
else info("Concise-rewrite hook already configured");
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
const healHook = configureInstallHealHook(SETTINGS_JSON);
|
|
2182
|
+
if (healHook.installed) {
|
|
2183
|
+
if (healHook.action === "added") success("Install self-heal added (restores missing tools before work starts — M108)");
|
|
2184
|
+
else if (healHook.action === "refreshed") success("Install self-heal refreshed");
|
|
2185
|
+
else info("Install self-heal already configured");
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2038
2188
|
heading("Graph Engine (CGC)");
|
|
2039
2189
|
installCgc();
|
|
2040
2190
|
|
|
@@ -2993,6 +3143,19 @@ const PROJECT_BIN_TOOLS = [
|
|
|
2993
3143
|
"gsd-t-model-tier-policy.cjs",
|
|
2994
3144
|
// M86 — Model-profile config + resolver CLI (standard/pro/premium tier-spend switch).
|
|
2995
3145
|
"gsd-t-model-profile.cjs",
|
|
3146
|
+
// M106 — Fallback detector. The PreToolUse guard prefers the project-local
|
|
3147
|
+
// copy; the verify gate dispatches to it by absolute path. Missing here means
|
|
3148
|
+
// every Write/Edit is DENIED (the guard halts rather than allowing unchecked),
|
|
3149
|
+
// so this entry is load-bearing — [[project_global_bin_propagation_gap]].
|
|
3150
|
+
"gsd-t-fallback-detect.cjs",
|
|
3151
|
+
// M107 — Concise rewriter, invoked by the Stop hook.
|
|
3152
|
+
"gsd-t-concise-rewrite.cjs",
|
|
3153
|
+
// M108 — Install self-check. Every project carries its own copy so it can
|
|
3154
|
+
// verify and repair itself even when the global install is what broke.
|
|
3155
|
+
"gsd-t-install-check.cjs",
|
|
3156
|
+
// M109 — project-history reader + rule miner, so /gsd-t-setup can write a
|
|
3157
|
+
// project CLAUDE.md from what actually happened rather than from a template.
|
|
3158
|
+
"gsd-t-project-history.cjs", "gsd-t-rule-mine.cjs",
|
|
2996
3159
|
// M89 — Auto-research gate classifier (classify a guessed claim as internal vs external;
|
|
2997
3160
|
// propagated to each registered project's bin/ so the workflow runCli fallback resolves
|
|
2998
3161
|
// downstream — per [[project_global_bin_propagation_gap]]).
|
|
@@ -3157,10 +3320,20 @@ function copyBinToolsToProject(projectDir, projectName) {
|
|
|
3157
3320
|
}
|
|
3158
3321
|
}
|
|
3159
3322
|
let copied = 0;
|
|
3323
|
+
// Tools this pass could NOT deliver. Every one is reported. A silent skip
|
|
3324
|
+
// here is how binvoice ran for weeks with 20 of 38 tools while every update
|
|
3325
|
+
// reported success — the missing files were never counted, so nothing looked
|
|
3326
|
+
// wrong. ([[project_global_bin_propagation_gap]], now 5 occurrences.)
|
|
3327
|
+
const notDelivered = [];
|
|
3160
3328
|
for (const tool of PROJECT_BIN_TOOLS) {
|
|
3161
3329
|
const src = path.join(PKG_ROOT, "bin", tool);
|
|
3162
3330
|
const dest = path.join(projectBinDir, tool);
|
|
3163
|
-
if (!fs.existsSync(src))
|
|
3331
|
+
if (!fs.existsSync(src)) {
|
|
3332
|
+
// The package promises a tool it does not contain. That is a packaging
|
|
3333
|
+
// defect and it affects EVERY project — it must never pass unremarked.
|
|
3334
|
+
notDelivered.push({ tool, why: "absent from the package being installed" });
|
|
3335
|
+
continue;
|
|
3336
|
+
}
|
|
3164
3337
|
let needsCopy = true;
|
|
3165
3338
|
if (fs.existsSync(dest)) {
|
|
3166
3339
|
try {
|
|
@@ -3168,7 +3341,7 @@ function copyBinToolsToProject(projectDir, projectName) {
|
|
|
3168
3341
|
const destContent = fs.readFileSync(dest, "utf8");
|
|
3169
3342
|
if (srcContent === destContent) needsCopy = false;
|
|
3170
3343
|
} catch {
|
|
3171
|
-
//
|
|
3344
|
+
// could not compare — copy, which is the safe direction
|
|
3172
3345
|
}
|
|
3173
3346
|
}
|
|
3174
3347
|
if (needsCopy) {
|
|
@@ -3177,10 +3350,17 @@ function copyBinToolsToProject(projectDir, projectName) {
|
|
|
3177
3350
|
try { fs.chmodSync(dest, 0o755); } catch {}
|
|
3178
3351
|
copied++;
|
|
3179
3352
|
} catch (e) {
|
|
3180
|
-
|
|
3353
|
+
notDelivered.push({ tool, why: e.message });
|
|
3181
3354
|
}
|
|
3182
3355
|
}
|
|
3183
3356
|
}
|
|
3357
|
+
if (notDelivered.length) {
|
|
3358
|
+
warn(`${projectName} — ${notDelivered.length} of ${PROJECT_BIN_TOOLS.length} tools were NOT delivered:`);
|
|
3359
|
+
for (const n of notDelivered) warn(` ${n.tool} — ${n.why}`);
|
|
3360
|
+
warn(` This project's install is incomplete. Tools that depend on the missing`);
|
|
3361
|
+
warn(` files will fail. Run 'gsd-t install-check --project ${projectDir}' after`);
|
|
3362
|
+
warn(` fixing the package.`);
|
|
3363
|
+
}
|
|
3184
3364
|
let cleaned = 0;
|
|
3185
3365
|
if (!_isGsdTSourcePackage(projectDir)) {
|
|
3186
3366
|
for (const stray of DEPRECATED_BIN_STRAYS) {
|
|
@@ -5369,6 +5549,20 @@ if (require.main === module) {
|
|
|
5369
5549
|
});
|
|
5370
5550
|
process.exit(res.status == null ? 1 : res.status);
|
|
5371
5551
|
}
|
|
5552
|
+
case "install-check": {
|
|
5553
|
+
// M108 — check this project's tools against the installed package, and
|
|
5554
|
+
// restore anything missing. `--check` reports without changing anything;
|
|
5555
|
+
// `--report` reads the shared log of every repair across all projects.
|
|
5556
|
+
const { spawnSync } = require("child_process");
|
|
5557
|
+
const js = path.join(__dirname, "gsd-t-install-check.cjs");
|
|
5558
|
+
if (!require("node:fs").existsSync(js)) {
|
|
5559
|
+
error(`gsd-t-install-check.cjs not found at ${js} — reinstall GSD-T`);
|
|
5560
|
+
process.exit(1);
|
|
5561
|
+
}
|
|
5562
|
+
const res = spawnSync(process.execPath, [js, ...args.slice(1)], { stdio: "inherit" });
|
|
5563
|
+
process.exit(res.status == null ? 1 : res.status);
|
|
5564
|
+
}
|
|
5565
|
+
|
|
5372
5566
|
case "pseudocode-style": {
|
|
5373
5567
|
// Contract v1.2.0 §1.1 — `gsd-t pseudocode-style (--doc <f> | --dir <d>)` thin
|
|
5374
5568
|
// dispatcher to the PseudoCode flow-line STYLE gate. Sibling of `guard-map`:
|
package/commands/gsd-t-setup.md
CHANGED
|
@@ -72,109 +72,133 @@ CLAUDE.md Analysis:
|
|
|
72
72
|
|
|
73
73
|
Note: "No existing CLAUDE.md — will generate from scratch."
|
|
74
74
|
|
|
75
|
-
## Step
|
|
75
|
+
## Step 3.5: Read what actually happened here
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
Before writing anything, read the project's own history. A rule that keeps
|
|
78
|
+
getting broken is the rule that most needs writing down, and nobody remembers
|
|
79
|
+
those on request — they have to be found.
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
```bash
|
|
82
|
+
node bin/gsd-t-project-history.cjs --project . --json
|
|
83
|
+
```
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
3. **Workflow Preferences**: "Any overrides to the global defaults? (Research Policy, Phase Flow)" (skip if user has no overrides)
|
|
84
|
-
4. **Deployed URLs**: "Production, staging, and local URLs?" (skip if found in .env or existing docs)
|
|
85
|
-
5. **Project-specific rules**: "Any 'never do' rules specific to this project?" (skip if existing CLAUDE.md already has them)
|
|
85
|
+
Three sources, cheapest first. Each reports whether it was there; a missing one
|
|
86
|
+
is **named**, never skipped in silence:
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- Anything already covered by the global CLAUDE.md
|
|
88
|
+
| Source | What it gives |
|
|
89
|
+
|---|---|
|
|
90
|
+
| Git | Files fixed the same way repeatedly, and real reverts |
|
|
91
|
+
| Decision log | Directives already recorded, with dates |
|
|
92
|
+
| Past sessions | What the user typed when something kept going wrong |
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
Session history is large — one project holds 315 MB — so the tool funnels it:
|
|
95
|
+
keep only the user's own turns, drop pasted logs, keep only complaint-shaped
|
|
96
|
+
lines. Under a second, and the result fits in context.
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
**If it exits 4, there is no history at all.** Do not carry on and write a
|
|
99
|
+
thinner file. Stop and ask:
|
|
97
100
|
|
|
98
|
-
```
|
|
99
|
-
|
|
101
|
+
```
|
|
102
|
+
Sources found: git 67 commits | decision log 1 line | sessions 0 | contracts 0
|
|
103
|
+
|
|
104
|
+
I can mine 0 rules from this project's history.
|
|
105
|
+
|
|
106
|
+
a) Write stack and commands only — the rules section left out, with the
|
|
107
|
+
reason written into the file. Not a normal CLAUDE.md.
|
|
108
|
+
b) You dictate the rules now.
|
|
109
|
+
c) Stop.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Whichever they pick, the gap goes **into the generated file** — "Rules: none
|
|
113
|
+
derivable, no project history" — so thinness stays visible rather than reading
|
|
114
|
+
as "this project has no rules."
|
|
100
115
|
|
|
101
|
-
##
|
|
102
|
-
**Expected branch**: {branch}
|
|
116
|
+
## Step 4: Show the rules found, and let the user tick them
|
|
103
117
|
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
Do **not** ask the user to recall rules. Mine every rule the project already
|
|
119
|
+
states, and let them confirm:
|
|
106
120
|
|
|
107
|
-
|
|
108
|
-
|
|
121
|
+
```bash
|
|
122
|
+
node bin/gsd-t-rule-mine.cjs --project . --top 12
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Six sources, ranked by how many agree — a rule found in three places ranks top,
|
|
126
|
+
because repetition is the evidence. The output is a tick-list:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
12 candidate rules for binvoice. Tick the ones that must NEVER be broken.
|
|
109
130
|
|
|
110
|
-
|
|
131
|
+
RULE SEEN IN
|
|
132
|
+
1 [ ] NEVER contact the buyer directly CLAUDE.md (HC-003)
|
|
133
|
+
2 [ ] TEXT-FIRST capture (enforced by a pre-write gate) CLAUDE.md (HC-004)
|
|
134
|
+
3 [ ] NEVER scan the whole page CLAUDE.md (HC-005)
|
|
111
135
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
| {component} | {path} |
|
|
136
|
+
Tick numbers (e.g. 1,3,4) or 'all':
|
|
137
|
+
```
|
|
115
138
|
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
The right-hand column is what makes this fast — the user is confirming
|
|
140
|
+
something they already said, not recalling it. **Cap the screen at 12.**
|
|
141
|
+
Anything below goes to `.gsd-t/setup-rules-full.md`; nothing is dropped.
|
|
118
142
|
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
|
|
122
|
-
- Workflows: docs/workflows.md
|
|
123
|
-
- Infrastructure: docs/infrastructure.md
|
|
143
|
+
**Never invent a rule.** Every one comes from somewhere in the project, and the
|
|
144
|
+
tick-list shows where. A rule the user did not tick is not inviolable — it may
|
|
145
|
+
still belong elsewhere in the file, but not in that section.
|
|
124
146
|
|
|
125
|
-
|
|
126
|
-
**Level {N} — {Name}** ({description}) <!-- default: Level 3 — Full Auto -->
|
|
147
|
+
**Determine these by reading, never by asking:**
|
|
127
148
|
|
|
128
|
-
|
|
129
|
-
|
|
149
|
+
| | How |
|
|
150
|
+
|---|---|
|
|
151
|
+
| Which branch | `git branch --show-current` |
|
|
152
|
+
| Where the repo misleads | Two version fields disagreeing, a legacy path that still looks live |
|
|
153
|
+
| Which files are dangerous | Fixed 5+ times in the git history |
|
|
154
|
+
| Stack, build, test | The manifest |
|
|
130
155
|
|
|
131
|
-
|
|
132
|
-
|
|
156
|
+
**Ask only if genuinely unresolvable:** the autonomy level when no existing
|
|
157
|
+
CLAUDE.md declares one, and deployed URLs when nothing records them.
|
|
133
158
|
|
|
134
|
-
|
|
135
|
-
{project-specific overrides, or omit section}
|
|
159
|
+
## Step 5: Generate CLAUDE.md
|
|
136
160
|
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
Use the mold at `templates/CLAUDE-project.md`. It is a real mold — do NOT copy
|
|
162
|
+
any existing project's file, and never GSD-T's own.
|
|
139
163
|
|
|
140
|
-
|
|
141
|
-
{Project-specific conventions that differ from or extend global defaults}
|
|
164
|
+
**Every section may be left out, with the reason stated. None may be padded.**
|
|
142
165
|
|
|
143
|
-
|
|
144
|
-
|
|
166
|
+
| Section | Include when | Fill from |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| Title + one-line what-this-is | Always | The manifest, the README |
|
|
169
|
+
| **Rules that can never be broken** | The user ticked at least one | Step 4's tick-list, verbatim |
|
|
170
|
+
| Where the repo misleads you | Reading the code gives a confident wrong answer | Determined, never asked |
|
|
171
|
+
| Files riskier than they look | Some file was fixed 5+ times | Git history |
|
|
172
|
+
| Where this differs from global | A genuine difference exists | Compared against `~/.claude/CLAUDE.md` |
|
|
173
|
+
| Stack and commands | Always | The manifest |
|
|
174
|
+
| Where things are written down | Always | Fixed pointers |
|
|
145
175
|
|
|
146
|
-
|
|
147
|
-
|
|
176
|
+
**Target 40–70 lines.** If it is longer, something in it is either restating a
|
|
177
|
+
global rule or repeating what the repo already says.
|
|
148
178
|
|
|
149
|
-
|
|
150
|
-
| Variable | Purpose | Default |
|
|
151
|
-
|----------|---------|---------|
|
|
152
|
-
| {VAR} | {purpose} | {default} |
|
|
179
|
+
### What must never appear
|
|
153
180
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
| Never | Why |
|
|
182
|
+
|---|---|
|
|
183
|
+
| Anything the global file already says | Three projects each paste the entire Destructive Action Guard verbatim — 15 wasted lines apiece |
|
|
184
|
+
| Anything a hook or gate enforces | The machine does not read this file |
|
|
185
|
+
| A version number, a line count, "currently in progress" | Wrong within a week. It belongs in `progress.md` |
|
|
186
|
+
| A file listing, a dependency list, a command count | The repo answers it, and answers it currently |
|
|
187
|
+
| A rule nobody stated | Every rule comes from the tick-list, and the tick-list shows its source |
|
|
158
188
|
|
|
159
|
-
|
|
160
|
-
{Project-specific rules only — don't repeat global rules}
|
|
189
|
+
### The line that matters most
|
|
161
190
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
- Contracts: .gsd-t/contracts/
|
|
166
|
-
- Domains: .gsd-t/domains/
|
|
191
|
+
A rule states **what must never happen and what breaks if it does**. If it is
|
|
192
|
+
enforced by a hook or a gate, say so — the reader should know a machine is
|
|
193
|
+
watching:
|
|
167
194
|
|
|
168
|
-
|
|
169
|
-
|
|
195
|
+
```
|
|
196
|
+
- **Never touch facebook.com** — no permissions, no requests, no DOM writes.
|
|
197
|
+
A single write turns a read-only observer into an actor on someone else's
|
|
198
|
+
account. Enforced by a pre-write gate.
|
|
170
199
|
```
|
|
171
200
|
|
|
172
|
-
|
|
173
|
-
- **NEVER duplicate** global CLAUDE.md content (Destructive Action Guard, Pre-Commit Gate, Prime Directives, etc.)
|
|
174
|
-
- **ALWAYS include**: Branch Guard, GSD-T Workflow, Current Status
|
|
175
|
-
- **Include if relevant**: Where Things Live, Testing, Code Patterns, Environment Variables
|
|
176
|
-
- **Omit if empty**: Deployed URLs (if not deployed), Architecture (if trivial), Workflow Preferences (if no overrides)
|
|
177
|
-
|
|
201
|
+
Not: *"Be careful with Facebook interactions."*
|
|
178
202
|
## Step 5.5: Quality North Star Configuration
|
|
179
203
|
|
|
180
204
|
After generating the CLAUDE.md content (Step 5) and before presenting it to the user, offer a Quality North Star section if one is not already present.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.10",
|
|
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",
|