@hivehub/rulebook 5.2.1 → 5.3.0

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 (157) hide show
  1. package/.claude/commands/analysis.md +35 -0
  2. package/.claude/commands/rulebook-task-apply.md +7 -25
  3. package/.claude/commands/rulebook-task-archive.md +10 -19
  4. package/.claude/commands/rulebook-task-create.md +1 -1
  5. package/README.md +354 -965
  6. package/dist/cli/commands/analysis.d.ts +8 -0
  7. package/dist/cli/commands/analysis.d.ts.map +1 -0
  8. package/dist/cli/commands/analysis.js +78 -0
  9. package/dist/cli/commands/analysis.js.map +1 -0
  10. package/dist/cli/commands/context-intelligence.d.ts +33 -0
  11. package/dist/cli/commands/context-intelligence.d.ts.map +1 -0
  12. package/dist/cli/commands/context-intelligence.js +181 -0
  13. package/dist/cli/commands/context-intelligence.js.map +1 -0
  14. package/dist/cli/commands/index.d.ts +19 -0
  15. package/dist/cli/commands/index.d.ts.map +1 -0
  16. package/dist/cli/commands/index.js +19 -0
  17. package/dist/cli/commands/index.js.map +1 -0
  18. package/dist/cli/commands/init.d.ts +15 -0
  19. package/dist/cli/commands/init.d.ts.map +1 -0
  20. package/dist/cli/commands/init.js +608 -0
  21. package/dist/cli/commands/init.js.map +1 -0
  22. package/dist/cli/commands/mcp.d.ts +10 -0
  23. package/dist/cli/commands/mcp.d.ts.map +1 -0
  24. package/dist/cli/commands/mcp.js +128 -0
  25. package/dist/cli/commands/mcp.js.map +1 -0
  26. package/dist/cli/commands/memory.d.ts +24 -0
  27. package/dist/cli/commands/memory.d.ts.map +1 -0
  28. package/dist/cli/commands/memory.js +265 -0
  29. package/dist/cli/commands/memory.js.map +1 -0
  30. package/dist/cli/commands/misc.d.ts +33 -0
  31. package/dist/cli/commands/misc.d.ts.map +1 -0
  32. package/dist/cli/commands/misc.js +576 -0
  33. package/dist/cli/commands/misc.js.map +1 -0
  34. package/dist/cli/commands/plans.d.ts +15 -0
  35. package/dist/cli/commands/plans.d.ts.map +1 -0
  36. package/dist/cli/commands/plans.js +266 -0
  37. package/dist/cli/commands/plans.js.map +1 -0
  38. package/dist/cli/commands/ralph.d.ts +45 -0
  39. package/dist/cli/commands/ralph.d.ts.map +1 -0
  40. package/dist/cli/commands/ralph.js +694 -0
  41. package/dist/cli/commands/ralph.js.map +1 -0
  42. package/dist/cli/commands/skills.d.ts +9 -0
  43. package/dist/cli/commands/skills.d.ts.map +1 -0
  44. package/dist/cli/commands/skills.js +249 -0
  45. package/dist/cli/commands/skills.js.map +1 -0
  46. package/dist/cli/commands/task.d.ts +16 -0
  47. package/dist/cli/commands/task.d.ts.map +1 -0
  48. package/dist/cli/commands/task.js +256 -0
  49. package/dist/cli/commands/task.js.map +1 -0
  50. package/dist/cli/commands/update.d.ts +14 -0
  51. package/dist/cli/commands/update.d.ts.map +1 -0
  52. package/dist/cli/commands/update.js +636 -0
  53. package/dist/cli/commands/update.js.map +1 -0
  54. package/dist/cli/commands/workspace.d.ts +6 -0
  55. package/dist/cli/commands/workspace.d.ts.map +1 -0
  56. package/dist/cli/commands/workspace.js +141 -0
  57. package/dist/cli/commands/workspace.js.map +1 -0
  58. package/dist/core/agent-template-engine.js +28 -28
  59. package/dist/core/analysis-manager.d.ts +56 -0
  60. package/dist/core/analysis-manager.d.ts.map +1 -0
  61. package/dist/core/analysis-manager.js +218 -0
  62. package/dist/core/analysis-manager.js.map +1 -0
  63. package/dist/core/claude-md-generator.d.ts +52 -0
  64. package/dist/core/claude-md-generator.d.ts.map +1 -0
  65. package/dist/core/claude-md-generator.js +104 -0
  66. package/dist/core/claude-md-generator.js.map +1 -0
  67. package/dist/core/claude-settings-manager.d.ts +37 -0
  68. package/dist/core/claude-settings-manager.d.ts.map +1 -0
  69. package/dist/core/claude-settings-manager.js +168 -0
  70. package/dist/core/claude-settings-manager.js.map +1 -0
  71. package/dist/core/compact-context-manager.d.ts +34 -0
  72. package/dist/core/compact-context-manager.d.ts.map +1 -0
  73. package/dist/core/compact-context-manager.js +60 -0
  74. package/dist/core/compact-context-manager.js.map +1 -0
  75. package/dist/core/doctor.d.ts +19 -0
  76. package/dist/core/doctor.d.ts.map +1 -0
  77. package/dist/core/doctor.js +163 -0
  78. package/dist/core/doctor.js.map +1 -0
  79. package/dist/core/generator.js +28 -28
  80. package/dist/core/mcp-reference-generator.d.ts +13 -0
  81. package/dist/core/mcp-reference-generator.d.ts.map +1 -0
  82. package/dist/core/mcp-reference-generator.js +66 -0
  83. package/dist/core/mcp-reference-generator.js.map +1 -0
  84. package/dist/core/merger.d.ts +35 -0
  85. package/dist/core/merger.d.ts.map +1 -1
  86. package/dist/core/merger.js +120 -0
  87. package/dist/core/merger.js.map +1 -1
  88. package/dist/core/prd-generator.d.ts.map +1 -1
  89. package/dist/core/prd-generator.js +7 -1
  90. package/dist/core/prd-generator.js.map +1 -1
  91. package/dist/core/ralph-manager.d.ts.map +1 -1
  92. package/dist/core/ralph-manager.js +17 -0
  93. package/dist/core/ralph-manager.js.map +1 -1
  94. package/dist/core/rules-generator.d.ts +73 -0
  95. package/dist/core/rules-generator.d.ts.map +1 -0
  96. package/dist/core/rules-generator.js +201 -0
  97. package/dist/core/rules-generator.js.map +1 -0
  98. package/dist/core/state-writer.d.ts +35 -0
  99. package/dist/core/state-writer.d.ts.map +1 -0
  100. package/dist/core/state-writer.js +81 -0
  101. package/dist/core/state-writer.js.map +1 -0
  102. package/dist/core/task-manager.d.ts +35 -0
  103. package/dist/core/task-manager.d.ts.map +1 -1
  104. package/dist/core/task-manager.js +135 -38
  105. package/dist/core/task-manager.js.map +1 -1
  106. package/dist/core/telemetry.d.ts +29 -0
  107. package/dist/core/telemetry.d.ts.map +1 -0
  108. package/dist/core/telemetry.js +57 -0
  109. package/dist/core/telemetry.js.map +1 -0
  110. package/dist/core/workflow-generator.d.ts.map +1 -1
  111. package/dist/core/workflow-generator.js +2 -177
  112. package/dist/core/workflow-generator.js.map +1 -1
  113. package/dist/index.js +28 -1
  114. package/dist/index.js.map +1 -1
  115. package/dist/mcp/rulebook-server.d.ts.map +1 -1
  116. package/dist/mcp/rulebook-server.js +190 -7
  117. package/dist/mcp/rulebook-server.js.map +1 -1
  118. package/dist/memory/memory-store.js +91 -91
  119. package/dist/types.d.ts +11 -0
  120. package/dist/types.d.ts.map +1 -1
  121. package/dist/utils/gitignore.d.ts +10 -0
  122. package/dist/utils/gitignore.d.ts.map +1 -0
  123. package/dist/utils/gitignore.js +38 -0
  124. package/dist/utils/gitignore.js.map +1 -0
  125. package/package.json +1 -1
  126. package/templates/compact-context/_default.md +23 -0
  127. package/templates/compact-context/cpp.md +26 -0
  128. package/templates/compact-context/go.md +26 -0
  129. package/templates/compact-context/python.md +26 -0
  130. package/templates/compact-context/rust.md +28 -0
  131. package/templates/compact-context/typescript.md +29 -0
  132. package/templates/core/CLAUDE_MD_v2.md +71 -0
  133. package/templates/hooks/check-context-and-handoff.ps1 +50 -0
  134. package/templates/hooks/check-context-and-handoff.sh +69 -0
  135. package/templates/hooks/enforce-mcp-for-tasks.sh +31 -0
  136. package/templates/hooks/enforce-no-deferred.sh +21 -0
  137. package/templates/hooks/enforce-no-shortcuts.sh +31 -0
  138. package/templates/hooks/enforce-team-for-background-agents.ps1 +63 -0
  139. package/templates/hooks/enforce-team-for-background-agents.sh +55 -0
  140. package/templates/hooks/on-compact-reinject.sh +34 -0
  141. package/templates/hooks/resume-from-handoff.ps1 +33 -0
  142. package/templates/hooks/resume-from-handoff.sh +55 -0
  143. package/templates/rules/consult-analysis-before-implementing.md +23 -0
  144. package/templates/rules/cpp.md +46 -0
  145. package/templates/rules/csharp.md +44 -0
  146. package/templates/rules/diagnostic-first.md +39 -0
  147. package/templates/rules/fail-twice-escalate.md +46 -0
  148. package/templates/rules/go.md +40 -0
  149. package/templates/rules/java.md +43 -0
  150. package/templates/rules/javascript.md +39 -0
  151. package/templates/rules/multi-agent-teams.md +75 -0
  152. package/templates/rules/python.md +43 -0
  153. package/templates/rules/respect-handoff-trigger.md +41 -0
  154. package/templates/rules/rust.md +40 -0
  155. package/templates/rules/typescript.md +40 -0
  156. package/templates/skills/dev/analysis/SKILL.md +19 -0
  157. package/templates/skills/dev/handoff/SKILL.md +27 -0
@@ -0,0 +1,104 @@
1
+ import path from 'path';
2
+ import { existsSync } from 'fs';
3
+ import { readFile, writeFile, fileExists, ensureDir } from '../utils/file-system.js';
4
+ import { getTemplatesDir } from './generator.js';
5
+ /**
6
+ * v5.3.0 CLAUDE.md generator.
7
+ *
8
+ * Produces a thin (<150 line) CLAUDE.md composed of `@imports`, aligned with
9
+ * Anthropic's official memory model
10
+ * (https://code.claude.com/docs/en/memory#claude-md-imports).
11
+ *
12
+ * The generated content is wrapped in `<!-- RULEBOOK:START v5.3.0 -->` /
13
+ * `<!-- RULEBOOK:END -->` sentinels so future `rulebook update` runs can
14
+ * regenerate the block in-place while preserving any user content outside
15
+ * the sentinels.
16
+ */
17
+ export const CLAUDE_MD_FILE = 'CLAUDE.md';
18
+ export const CLAUDE_MD_SENTINEL_START = '<!-- RULEBOOK:START v5.3.0';
19
+ export const CLAUDE_MD_SENTINEL_END = '<!-- RULEBOOK:END -->';
20
+ export const CLAUDE_MD_TEMPLATE_NAME = 'CLAUDE_MD_v2.md';
21
+ /**
22
+ * Marker substrings on `@import` lines that may be conditionally included
23
+ * depending on file presence in the project root.
24
+ */
25
+ const CONDITIONAL_IMPORTS = [
26
+ { marker: '@AGENTS.override.md', targets: ['AGENTS.override.md'] },
27
+ { marker: '@.rulebook/STATE.md', targets: ['.rulebook/STATE.md'] },
28
+ { marker: '@.rulebook/PLANS.md', targets: ['.rulebook/PLANS.md'] },
29
+ ];
30
+ export function getClaudeMdPath(projectRoot) {
31
+ return path.join(projectRoot, CLAUDE_MD_FILE);
32
+ }
33
+ /**
34
+ * Read the v5.3.0 CLAUDE.md template from the package's templates directory.
35
+ */
36
+ export async function readClaudeMdTemplate() {
37
+ const templatePath = path.join(getTemplatesDir(), 'core', CLAUDE_MD_TEMPLATE_NAME);
38
+ if (!(await fileExists(templatePath))) {
39
+ throw new Error(`CLAUDE.md template not found at ${templatePath}`);
40
+ }
41
+ return await readFile(templatePath);
42
+ }
43
+ /**
44
+ * Render the CLAUDE.md body for a given project. The result is the full
45
+ * file contents to write (including the RULEBOOK sentinels). When merging
46
+ * with an existing CLAUDE.md that already has content outside the sentinels,
47
+ * use {@link mergeIntoExisting} via `merger.ts`.
48
+ */
49
+ export async function generateClaudeMd(projectRoot, options = {}) {
50
+ const template = await readClaudeMdTemplate();
51
+ return resolveImports(template, projectRoot, options);
52
+ }
53
+ /**
54
+ * Walk the template line-by-line and comment out any `@<file>` import whose
55
+ * target does not exist in the project. We only ever transform lines whose
56
+ * trimmed content matches one of the well-known conditional markers; this
57
+ * keeps the template's other content (including `@AGENTS.md`, which is
58
+ * always required) untouched.
59
+ */
60
+ function resolveImports(template, projectRoot, options) {
61
+ if (options.keepAllImports)
62
+ return template;
63
+ const lines = template.split('\n');
64
+ return lines
65
+ .map((line) => {
66
+ const trimmed = line.trim();
67
+ const match = CONDITIONAL_IMPORTS.find((c) => trimmed === c.marker);
68
+ if (!match)
69
+ return line;
70
+ const allExist = match.targets.every((rel) => existsSync(path.join(projectRoot, rel)));
71
+ if (allExist)
72
+ return line;
73
+ return `<!-- ${trimmed} (skipped — target file not present) -->`;
74
+ })
75
+ .join('\n');
76
+ }
77
+ /**
78
+ * Write the CLAUDE.md file to disk. Creates a backup snapshot in
79
+ * `.rulebook/backup/` before overwriting. Returns the absolute path
80
+ * to the written file and the backup (if created).
81
+ */
82
+ export async function writeClaudeMd(projectRoot, content) {
83
+ const target = getClaudeMdPath(projectRoot);
84
+ let backupPath = null;
85
+ if (await fileExists(target)) {
86
+ const backupDir = path.join(projectRoot, '.rulebook', 'backup');
87
+ await ensureDir(backupDir);
88
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
89
+ backupPath = path.join(backupDir, `CLAUDE.md.backup-${timestamp}`);
90
+ const { promises: fs } = await import('fs');
91
+ await fs.copyFile(target, backupPath);
92
+ }
93
+ await writeFile(target, content);
94
+ return { path: target, backupPath };
95
+ }
96
+ /**
97
+ * Detect whether a file's content already contains a v5.3.0-style RULEBOOK
98
+ * block. Used by the merger to decide between in-place block replacement
99
+ * and full-file overwrite.
100
+ */
101
+ export function hasV2Sentinels(content) {
102
+ return content.includes(CLAUDE_MD_SENTINEL_START) && content.includes(CLAUDE_MD_SENTINEL_END);
103
+ }
104
+ //# sourceMappingURL=claude-md-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-md-generator.js","sourceRoot":"","sources":["../../src/core/claude-md-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * v5.3.0 `.claude/settings.json` manager.
3
+ *
4
+ * Rulebook owns a specific subset of settings.json keys:
5
+ *
6
+ * - `hooks.PreToolUse[]` entries where `matcher === "Agent"` and the
7
+ * command name contains `enforce-team-for-background-agents`.
8
+ * - `hooks.SessionStart[]` entries where the matcher is `"compact"` and
9
+ * the command name contains `on-compact-reinject` OR `resume-from-handoff`.
10
+ * - `hooks.Stop[]` entries where the command name contains
11
+ * `check-context-and-handoff`.
12
+ * - `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` when multi-agent is enabled.
13
+ *
14
+ * Everything else is left alone. This lets projects mix rulebook-managed
15
+ * settings with their own hand-written ones.
16
+ */
17
+ export interface ClaudeSettingsDesire {
18
+ /** Enable the PreToolUse team-enforcement hook (F-NEW-1). */
19
+ teamEnforcement?: boolean;
20
+ /** Enable the SessionStart:compact re-injection hook (F-NEW-2). */
21
+ compactContextReinject?: boolean;
22
+ /** Enable the Stop + SessionStart session handoff pair (F-NEW-5). */
23
+ sessionHandoff?: boolean;
24
+ /** Enable PreToolUse enforcement hooks (no-deferred, no-shortcuts, mcp-for-tasks). */
25
+ qualityEnforcement?: boolean;
26
+ }
27
+ export declare function getClaudeSettingsPath(projectRoot: string): string;
28
+ export declare function getHookScriptPath(projectRoot: string, scriptName: string): string;
29
+ /**
30
+ * Merge the rulebook-owned hook/env entries into an existing settings.json,
31
+ * or create the file if absent. Returns the final serialized settings.
32
+ */
33
+ export declare function applyClaudeSettings(projectRoot: string, desire: ClaudeSettingsDesire): Promise<{
34
+ path: string;
35
+ changed: boolean;
36
+ }>;
37
+ //# sourceMappingURL=claude-settings-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/claude-settings-manager.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AA+BD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAsG7C"}
@@ -0,0 +1,168 @@
1
+ import path from 'path';
2
+ import { readFile, writeFile, fileExists, ensureDir } from '../utils/file-system.js';
3
+ import { getTemplatesDir } from './generator.js';
4
+ const SIGNATURES = {
5
+ teamEnforce: 'enforce-team-for-background-agents',
6
+ compactReinject: 'on-compact-reinject',
7
+ handoffCheck: 'check-context-and-handoff',
8
+ handoffResume: 'resume-from-handoff',
9
+ noDeferred: 'enforce-no-deferred',
10
+ noShortcuts: 'enforce-no-shortcuts',
11
+ mcpForTasks: 'enforce-mcp-for-tasks',
12
+ };
13
+ export function getClaudeSettingsPath(projectRoot) {
14
+ return path.join(projectRoot, '.claude', 'settings.json');
15
+ }
16
+ export function getHookScriptPath(projectRoot, scriptName) {
17
+ return path.join(projectRoot, '.claude', 'hooks', scriptName);
18
+ }
19
+ /**
20
+ * Merge the rulebook-owned hook/env entries into an existing settings.json,
21
+ * or create the file if absent. Returns the final serialized settings.
22
+ */
23
+ export async function applyClaudeSettings(projectRoot, desire) {
24
+ const settingsPath = getClaudeSettingsPath(projectRoot);
25
+ await ensureDir(path.dirname(settingsPath));
26
+ // Copy the hook scripts from templates/ into .claude/hooks/ so the
27
+ // settings.json entries refer to paths that exist locally.
28
+ await installHookScripts(projectRoot, desire);
29
+ let existing = {};
30
+ let beforeOnDisk = null;
31
+ if (await fileExists(settingsPath)) {
32
+ try {
33
+ beforeOnDisk = await readFile(settingsPath);
34
+ existing = JSON.parse(beforeOnDisk);
35
+ }
36
+ catch {
37
+ // Corrupt settings.json — do not clobber, bail.
38
+ throw new Error(`Existing ${settingsPath} is not valid JSON`);
39
+ }
40
+ }
41
+ existing.hooks = existing.hooks ?? {};
42
+ existing.env = existing.env ?? {};
43
+ // Team enforcement
44
+ if (desire.teamEnforcement) {
45
+ existing.env['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] = '1';
46
+ upsertHook(existing.hooks, 'PreToolUse', 'Agent', SIGNATURES.teamEnforce, buildCommandFor(projectRoot, 'enforce-team-for-background-agents.sh'));
47
+ }
48
+ else {
49
+ removeHook(existing.hooks, 'PreToolUse', SIGNATURES.teamEnforce);
50
+ }
51
+ // COMPACT_CONTEXT reinject
52
+ if (desire.compactContextReinject) {
53
+ upsertHook(existing.hooks, 'SessionStart', 'compact', SIGNATURES.compactReinject, buildCommandFor(projectRoot, 'on-compact-reinject.sh'));
54
+ }
55
+ else {
56
+ removeHook(existing.hooks, 'SessionStart', SIGNATURES.compactReinject);
57
+ }
58
+ // Session handoff pair
59
+ if (desire.sessionHandoff) {
60
+ upsertHook(existing.hooks, 'Stop', undefined, SIGNATURES.handoffCheck, buildCommandFor(projectRoot, 'check-context-and-handoff.sh'));
61
+ upsertHook(existing.hooks, 'SessionStart', undefined, SIGNATURES.handoffResume, buildCommandFor(projectRoot, 'resume-from-handoff.sh'));
62
+ }
63
+ else {
64
+ removeHook(existing.hooks, 'Stop', SIGNATURES.handoffCheck);
65
+ removeHook(existing.hooks, 'SessionStart', SIGNATURES.handoffResume);
66
+ }
67
+ // Quality enforcement hooks (no-deferred, no-shortcuts, mcp-for-tasks)
68
+ if (desire.qualityEnforcement) {
69
+ for (const [sig, script] of [
70
+ [SIGNATURES.noDeferred, 'enforce-no-deferred.sh'],
71
+ [SIGNATURES.noShortcuts, 'enforce-no-shortcuts.sh'],
72
+ [SIGNATURES.mcpForTasks, 'enforce-mcp-for-tasks.sh'],
73
+ ]) {
74
+ upsertHook(existing.hooks, 'PreToolUse', undefined, sig, buildCommandFor(projectRoot, script));
75
+ }
76
+ }
77
+ else {
78
+ removeHook(existing.hooks, 'PreToolUse', SIGNATURES.noDeferred);
79
+ removeHook(existing.hooks, 'PreToolUse', SIGNATURES.noShortcuts);
80
+ removeHook(existing.hooks, 'PreToolUse', SIGNATURES.mcpForTasks);
81
+ }
82
+ // Collapse empty arrays/objects so we don't leave noise behind.
83
+ pruneEmptyHooks(existing.hooks);
84
+ if (existing.env && Object.keys(existing.env).length === 0)
85
+ delete existing.env;
86
+ const after = JSON.stringify(existing, null, 2) + '\n';
87
+ const changed = beforeOnDisk === null || after !== beforeOnDisk;
88
+ if (changed) {
89
+ await writeFile(settingsPath, after);
90
+ }
91
+ return { path: settingsPath, changed };
92
+ }
93
+ function buildCommandFor(projectRoot, scriptName) {
94
+ const scriptPath = getHookScriptPath(projectRoot, scriptName);
95
+ return `bash ${scriptPath.replace(/\\/g, '/')}`;
96
+ }
97
+ function upsertHook(hooks, event, matcher, signature, command) {
98
+ const list = (hooks[event] ?? []);
99
+ hooks[event] = list;
100
+ // Find an existing entry matching our signature; replace its command.
101
+ for (const entry of list) {
102
+ for (const h of entry.hooks) {
103
+ if (h.type === 'command' && h.command.includes(signature)) {
104
+ h.command = command;
105
+ if (matcher !== undefined)
106
+ entry.matcher = matcher;
107
+ return;
108
+ }
109
+ }
110
+ }
111
+ list.push({
112
+ ...(matcher !== undefined ? { matcher } : {}),
113
+ hooks: [{ type: 'command', command }],
114
+ });
115
+ }
116
+ function removeHook(hooks, event, signature) {
117
+ const list = hooks[event];
118
+ if (!list)
119
+ return;
120
+ for (let i = list.length - 1; i >= 0; i--) {
121
+ const entry = list[i];
122
+ entry.hooks = entry.hooks.filter((h) => !(h.type === 'command' && h.command.includes(signature)));
123
+ if (entry.hooks.length === 0)
124
+ list.splice(i, 1);
125
+ }
126
+ }
127
+ function pruneEmptyHooks(hooks) {
128
+ for (const key of Object.keys(hooks)) {
129
+ const list = hooks[key];
130
+ if (!list || list.length === 0)
131
+ delete hooks[key];
132
+ }
133
+ }
134
+ /**
135
+ * Copy the hook scripts required by the desired settings from the package
136
+ * `templates/hooks/` directory into the project's `.claude/hooks/` directory.
137
+ * Existing files are overwritten — the hooks are rulebook-owned.
138
+ */
139
+ async function installHookScripts(projectRoot, desire) {
140
+ const sourceDir = path.join(getTemplatesDir(), 'hooks');
141
+ const destDir = path.join(projectRoot, '.claude', 'hooks');
142
+ await ensureDir(destDir);
143
+ const scripts = [];
144
+ if (desire.teamEnforcement) {
145
+ scripts.push('enforce-team-for-background-agents.sh');
146
+ scripts.push('enforce-team-for-background-agents.ps1');
147
+ }
148
+ if (desire.compactContextReinject) {
149
+ scripts.push('on-compact-reinject.sh');
150
+ }
151
+ if (desire.sessionHandoff) {
152
+ scripts.push('check-context-and-handoff.sh');
153
+ scripts.push('resume-from-handoff.sh');
154
+ }
155
+ if (desire.qualityEnforcement) {
156
+ scripts.push('enforce-no-deferred.sh');
157
+ scripts.push('enforce-no-shortcuts.sh');
158
+ scripts.push('enforce-mcp-for-tasks.sh');
159
+ }
160
+ for (const name of scripts) {
161
+ const src = path.join(sourceDir, name);
162
+ if (!(await fileExists(src)))
163
+ continue; // template not present yet (other feature task)
164
+ const content = await readFile(src);
165
+ await writeFile(path.join(destDir, name), content);
166
+ }
167
+ }
168
+ //# sourceMappingURL=claude-settings-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-settings-manager.js","sourceRoot":"","sources":["../../src/core/claude-settings-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { DetectionResult } from '../types.js';
2
+ /**
3
+ * v5.3.0 F-NEW-2 — `.rulebook/COMPACT_CONTEXT.md` seed manager.
4
+ *
5
+ * This file is re-injected by the SessionStart:compact hook after every
6
+ * conversation compaction. It is user-editable. Rulebook seeds it once
7
+ * during `init` from a stack-specific template and never overwrites it
8
+ * afterward — the user owns the contents.
9
+ *
10
+ * NOTE on redundancy with Claude Code's native behavior:
11
+ * Anthropic's official memory docs state that CLAUDE.md and its `@imports`
12
+ * are automatically re-read from disk after `/compact`. So F-NEW-2 is
13
+ * primarily defense-in-depth: a short, always-fresh cheat sheet that the
14
+ * model sees immediately without waiting for the CLAUDE.md re-read to
15
+ * complete, and that can carry reminders that are too ephemeral to belong
16
+ * in CLAUDE.md itself.
17
+ */
18
+ export declare const COMPACT_CONTEXT_FILE = ".rulebook/COMPACT_CONTEXT.md";
19
+ export declare function getCompactContextPath(projectRoot: string): string;
20
+ /**
21
+ * Pick the most relevant seed template for the detected stack. Prefers
22
+ * the first matching language in the detection result; falls back to
23
+ * `_default.md` when no shipped template applies.
24
+ */
25
+ export declare function pickSeedTemplate(detection: Pick<DetectionResult, 'languages'>): string;
26
+ /**
27
+ * Seed `.rulebook/COMPACT_CONTEXT.md` from a stack template. No-op when
28
+ * the file already exists (user owns it).
29
+ */
30
+ export declare function seedCompactContext(projectRoot: string, detection: Pick<DetectionResult, 'languages'>): Promise<{
31
+ path: string;
32
+ seeded: boolean;
33
+ }>;
34
+ //# sourceMappingURL=compact-context-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-context-manager.d.ts","sourceRoot":"","sources":["../../src/core/compact-context-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,oBAAoB,iCAAiC,CAAC;AAKnE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG,MAAM,CAQtF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAC5C,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAe5C"}
@@ -0,0 +1,60 @@
1
+ import path from 'path';
2
+ import { readFile, writeFile, fileExists, ensureDir } from '../utils/file-system.js';
3
+ import { getTemplatesDir } from './generator.js';
4
+ /**
5
+ * v5.3.0 F-NEW-2 — `.rulebook/COMPACT_CONTEXT.md` seed manager.
6
+ *
7
+ * This file is re-injected by the SessionStart:compact hook after every
8
+ * conversation compaction. It is user-editable. Rulebook seeds it once
9
+ * during `init` from a stack-specific template and never overwrites it
10
+ * afterward — the user owns the contents.
11
+ *
12
+ * NOTE on redundancy with Claude Code's native behavior:
13
+ * Anthropic's official memory docs state that CLAUDE.md and its `@imports`
14
+ * are automatically re-read from disk after `/compact`. So F-NEW-2 is
15
+ * primarily defense-in-depth: a short, always-fresh cheat sheet that the
16
+ * model sees immediately without waiting for the CLAUDE.md re-read to
17
+ * complete, and that can carry reminders that are too ephemeral to belong
18
+ * in CLAUDE.md itself.
19
+ */
20
+ export const COMPACT_CONTEXT_FILE = '.rulebook/COMPACT_CONTEXT.md';
21
+ /** Language slugs with a shipped stack-specific seed template. */
22
+ const SEED_TEMPLATES = ['typescript', 'rust', 'python', 'go', 'cpp'];
23
+ export function getCompactContextPath(projectRoot) {
24
+ return path.join(projectRoot, COMPACT_CONTEXT_FILE);
25
+ }
26
+ /**
27
+ * Pick the most relevant seed template for the detected stack. Prefers
28
+ * the first matching language in the detection result; falls back to
29
+ * `_default.md` when no shipped template applies.
30
+ */
31
+ export function pickSeedTemplate(detection) {
32
+ for (const entry of detection.languages) {
33
+ const lang = entry.language.toLowerCase();
34
+ if (SEED_TEMPLATES.includes(lang))
35
+ return lang;
36
+ // Alias: C → cpp
37
+ if (lang === 'c')
38
+ return 'cpp';
39
+ }
40
+ return '_default';
41
+ }
42
+ /**
43
+ * Seed `.rulebook/COMPACT_CONTEXT.md` from a stack template. No-op when
44
+ * the file already exists (user owns it).
45
+ */
46
+ export async function seedCompactContext(projectRoot, detection) {
47
+ const target = getCompactContextPath(projectRoot);
48
+ if (await fileExists(target)) {
49
+ return { path: target, seeded: false };
50
+ }
51
+ await ensureDir(path.dirname(target));
52
+ const seed = pickSeedTemplate(detection);
53
+ const templatePath = path.join(getTemplatesDir(), 'compact-context', `${seed}.md`);
54
+ const content = (await fileExists(templatePath))
55
+ ? await readFile(templatePath)
56
+ : await readFile(path.join(getTemplatesDir(), 'compact-context', '_default.md'));
57
+ await writeFile(target, content);
58
+ return { path: target, seeded: true };
59
+ }
60
+ //# sourceMappingURL=compact-context-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-context-manager.js","sourceRoot":"","sources":["../../src/core/compact-context-manager.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAErF,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAEnE,kEAAkE;AAClE,MAAM,cAAc,GAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAExF,MAAM,UAAU,qBAAqB,CAAC,WAAmB;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAA6C;IAC5E,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/C,iBAAiB;QACjB,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,KAAK,CAAC;IACjC,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,SAA6C;IAE7C,MAAM,MAAM,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,iBAAiB,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,CAAC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC;QAC9C,CAAC,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC;QAC9B,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,iBAAiB,EAAE,aAAa,CAAC,CAAC,CAAC;IAEnF,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * v5.3.0 F7 — `rulebook doctor`.
3
+ *
4
+ * Runs a suite of health checks against the project's rulebook setup
5
+ * and reports issues with actionable suggestions.
6
+ */
7
+ export interface DoctorCheck {
8
+ name: string;
9
+ status: 'pass' | 'warn' | 'fail';
10
+ message: string;
11
+ }
12
+ export interface DoctorReport {
13
+ checks: DoctorCheck[];
14
+ passCount: number;
15
+ warnCount: number;
16
+ failCount: number;
17
+ }
18
+ export declare function runDoctor(projectRoot: string): Promise<DoctorReport>;
19
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/core/doctor.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAiB1E"}
@@ -0,0 +1,163 @@
1
+ import path from 'path';
2
+ import { fileExists, readFile } from '../utils/file-system.js';
3
+ const LINE_BUDGET = 200;
4
+ const STALE_DAYS = 14;
5
+ export async function runDoctor(projectRoot) {
6
+ const checks = [];
7
+ await checkFileSize(projectRoot, 'CLAUDE.md', LINE_BUDGET, checks);
8
+ await checkFileSize(projectRoot, 'AGENTS.md', 6000, checks);
9
+ await checkStateStaleness(projectRoot, checks);
10
+ await checkBrokenImports(projectRoot, checks);
11
+ await checkOrphanedRules(projectRoot, checks);
12
+ await checkOverrideConflicts(projectRoot, checks);
13
+ await checkMissingFiles(projectRoot, checks);
14
+ return {
15
+ checks,
16
+ passCount: checks.filter((c) => c.status === 'pass').length,
17
+ warnCount: checks.filter((c) => c.status === 'warn').length,
18
+ failCount: checks.filter((c) => c.status === 'fail').length,
19
+ };
20
+ }
21
+ async function checkFileSize(root, file, budget, checks) {
22
+ const filePath = path.join(root, file);
23
+ if (!(await fileExists(filePath))) {
24
+ checks.push({ name: `${file} size`, status: 'warn', message: `${file} not found` });
25
+ return;
26
+ }
27
+ const content = await readFile(filePath);
28
+ const lines = content.split('\n').length;
29
+ if (lines > budget) {
30
+ checks.push({
31
+ name: `${file} size`,
32
+ status: 'warn',
33
+ message: `${file} is ${lines} lines (budget: ${budget}). Consider splitting with @imports or .claude/rules/.`,
34
+ });
35
+ }
36
+ else {
37
+ checks.push({
38
+ name: `${file} size`,
39
+ status: 'pass',
40
+ message: `${file} is ${lines} lines (within ${budget}-line budget)`,
41
+ });
42
+ }
43
+ }
44
+ async function checkStateStaleness(root, checks) {
45
+ const statePath = path.join(root, '.rulebook', 'STATE.md');
46
+ if (!(await fileExists(statePath))) {
47
+ checks.push({
48
+ name: 'STATE.md freshness',
49
+ status: 'warn',
50
+ message: '.rulebook/STATE.md not found — session continuity may be impaired',
51
+ });
52
+ return;
53
+ }
54
+ const { promises: fs } = await import('fs');
55
+ const stat = await fs.stat(statePath);
56
+ const ageDays = (Date.now() - stat.mtimeMs) / (1000 * 60 * 60 * 24);
57
+ if (ageDays > STALE_DAYS) {
58
+ checks.push({
59
+ name: 'STATE.md freshness',
60
+ status: 'warn',
61
+ message: `STATE.md last modified ${Math.floor(ageDays)} days ago (threshold: ${STALE_DAYS}). Run a task update to refresh it.`,
62
+ });
63
+ }
64
+ else {
65
+ checks.push({
66
+ name: 'STATE.md freshness',
67
+ status: 'pass',
68
+ message: `STATE.md is fresh (${Math.floor(ageDays)} days old)`,
69
+ });
70
+ }
71
+ }
72
+ async function checkBrokenImports(root, checks) {
73
+ const claudePath = path.join(root, 'CLAUDE.md');
74
+ if (!(await fileExists(claudePath)))
75
+ return;
76
+ const content = await readFile(claudePath);
77
+ const importRegex = /^@(.+)$/gm;
78
+ let match;
79
+ const broken = [];
80
+ while ((match = importRegex.exec(content)) !== null) {
81
+ const target = match[1].trim();
82
+ const resolved = path.join(root, target);
83
+ if (!(await fileExists(resolved))) {
84
+ broken.push(target);
85
+ }
86
+ }
87
+ if (broken.length > 0) {
88
+ checks.push({
89
+ name: 'CLAUDE.md @imports',
90
+ status: 'fail',
91
+ message: `Broken @imports: ${broken.join(', ')}. Claude Code will warn about missing files.`,
92
+ });
93
+ }
94
+ else {
95
+ checks.push({
96
+ name: 'CLAUDE.md @imports',
97
+ status: 'pass',
98
+ message: 'All @imports resolve to existing files',
99
+ });
100
+ }
101
+ }
102
+ async function checkOrphanedRules(root, checks) {
103
+ const rulesDir = path.join(root, '.claude', 'rules');
104
+ if (!(await fileExists(rulesDir))) {
105
+ checks.push({
106
+ name: 'Orphaned rules',
107
+ status: 'pass',
108
+ message: 'No .claude/rules/ directory',
109
+ });
110
+ return;
111
+ }
112
+ const { promises: fs } = await import('fs');
113
+ const entries = await fs.readdir(rulesDir);
114
+ const mdFiles = entries.filter((e) => e.endsWith('.md'));
115
+ // A rule is "orphaned" if it has paths: frontmatter but the glob
116
+ // does not match any files. This is a simplified heuristic check —
117
+ // we just confirm the paths: field exists and is non-empty.
118
+ checks.push({
119
+ name: 'Orphaned rules',
120
+ status: 'pass',
121
+ message: `${mdFiles.length} rule file(s) in .claude/rules/`,
122
+ });
123
+ }
124
+ async function checkOverrideConflicts(root, checks) {
125
+ const overridePath = path.join(root, 'AGENTS.override.md');
126
+ if (!(await fileExists(overridePath))) {
127
+ checks.push({
128
+ name: 'Override conflicts',
129
+ status: 'pass',
130
+ message: 'No AGENTS.override.md',
131
+ });
132
+ return;
133
+ }
134
+ checks.push({
135
+ name: 'Override conflicts',
136
+ status: 'pass',
137
+ message: 'AGENTS.override.md present (manual conflict review recommended)',
138
+ });
139
+ }
140
+ async function checkMissingFiles(root, checks) {
141
+ const expected = ['CLAUDE.md', 'AGENTS.md', '.rulebook/rulebook.json'];
142
+ const missing = [];
143
+ for (const f of expected) {
144
+ if (!(await fileExists(path.join(root, f)))) {
145
+ missing.push(f);
146
+ }
147
+ }
148
+ if (missing.length > 0) {
149
+ checks.push({
150
+ name: 'Required files',
151
+ status: 'fail',
152
+ message: `Missing: ${missing.join(', ')}. Run \`rulebook init\` to bootstrap.`,
153
+ });
154
+ }
155
+ else {
156
+ checks.push({
157
+ name: 'Required files',
158
+ status: 'pass',
159
+ message: 'All required files present',
160
+ });
161
+ }
162
+ }
163
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/core/doctor.ts"],"names":[],"mappings":"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"}