@hivehub/rulebook 3.4.2 → 4.0.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 (148) hide show
  1. package/.claude/commands/continue.md +33 -0
  2. package/.claude-plugin/marketplace.json +28 -29
  3. package/.claude-plugin/plugin.json +8 -8
  4. package/README.md +32 -144
  5. package/dist/agents/ralph-parser.d.ts +41 -1
  6. package/dist/agents/ralph-parser.d.ts.map +1 -1
  7. package/dist/agents/ralph-parser.js +202 -14
  8. package/dist/agents/ralph-parser.js.map +1 -1
  9. package/dist/cli/commands.d.ts +65 -0
  10. package/dist/cli/commands.d.ts.map +1 -1
  11. package/dist/cli/commands.js +837 -61
  12. package/dist/cli/commands.js.map +1 -1
  13. package/dist/core/agent-manager.d.ts +7 -0
  14. package/dist/core/agent-manager.d.ts.map +1 -1
  15. package/dist/core/agent-manager.js +150 -3
  16. package/dist/core/agent-manager.js.map +1 -1
  17. package/dist/core/claude-mcp.d.ts +17 -0
  18. package/dist/core/claude-mcp.d.ts.map +1 -1
  19. package/dist/core/claude-mcp.js +90 -6
  20. package/dist/core/claude-mcp.js.map +1 -1
  21. package/dist/core/config-manager.d.ts.map +1 -1
  22. package/dist/core/config-manager.js +40 -0
  23. package/dist/core/config-manager.js.map +1 -1
  24. package/dist/core/cursor-mdc-generator.d.ts +30 -0
  25. package/dist/core/cursor-mdc-generator.d.ts.map +1 -0
  26. package/dist/core/cursor-mdc-generator.js +98 -0
  27. package/dist/core/cursor-mdc-generator.js.map +1 -0
  28. package/dist/core/detector.d.ts +25 -1
  29. package/dist/core/detector.d.ts.map +1 -1
  30. package/dist/core/detector.js +321 -1
  31. package/dist/core/detector.js.map +1 -1
  32. package/dist/core/generator.d.ts +10 -0
  33. package/dist/core/generator.d.ts.map +1 -1
  34. package/dist/core/generator.js +177 -3
  35. package/dist/core/generator.js.map +1 -1
  36. package/dist/core/github-issues-importer.d.ts +82 -0
  37. package/dist/core/github-issues-importer.d.ts.map +1 -0
  38. package/dist/core/github-issues-importer.js +161 -0
  39. package/dist/core/github-issues-importer.js.map +1 -0
  40. package/dist/core/health-scorer.d.ts +39 -0
  41. package/dist/core/health-scorer.d.ts.map +1 -1
  42. package/dist/core/health-scorer.js +256 -13
  43. package/dist/core/health-scorer.js.map +1 -1
  44. package/dist/core/iteration-tracker.d.ts +28 -0
  45. package/dist/core/iteration-tracker.d.ts.map +1 -1
  46. package/dist/core/iteration-tracker.js +86 -0
  47. package/dist/core/iteration-tracker.js.map +1 -1
  48. package/dist/core/multi-tool-generator.d.ts +59 -0
  49. package/dist/core/multi-tool-generator.d.ts.map +1 -0
  50. package/dist/core/multi-tool-generator.js +157 -0
  51. package/dist/core/multi-tool-generator.js.map +1 -0
  52. package/dist/core/override-manager.d.ts +23 -0
  53. package/dist/core/override-manager.d.ts.map +1 -0
  54. package/dist/core/override-manager.js +82 -0
  55. package/dist/core/override-manager.js.map +1 -0
  56. package/dist/core/plans-manager.d.ts +46 -0
  57. package/dist/core/plans-manager.d.ts.map +1 -0
  58. package/dist/core/plans-manager.js +158 -0
  59. package/dist/core/plans-manager.js.map +1 -0
  60. package/dist/core/prd-generator.d.ts +12 -0
  61. package/dist/core/prd-generator.d.ts.map +1 -1
  62. package/dist/core/prd-generator.js +91 -2
  63. package/dist/core/prd-generator.js.map +1 -1
  64. package/dist/core/ralph-manager.d.ts +47 -1
  65. package/dist/core/ralph-manager.d.ts.map +1 -1
  66. package/dist/core/ralph-manager.js +107 -0
  67. package/dist/core/ralph-manager.js.map +1 -1
  68. package/dist/core/ralph-parallel.d.ts +55 -0
  69. package/dist/core/ralph-parallel.d.ts.map +1 -0
  70. package/dist/core/ralph-parallel.js +201 -0
  71. package/dist/core/ralph-parallel.js.map +1 -0
  72. package/dist/core/ralph-plan-checkpoint.d.ts +58 -0
  73. package/dist/core/ralph-plan-checkpoint.d.ts.map +1 -0
  74. package/dist/core/ralph-plan-checkpoint.js +154 -0
  75. package/dist/core/ralph-plan-checkpoint.js.map +1 -0
  76. package/dist/core/ralph-scripts.d.ts +12 -0
  77. package/dist/core/ralph-scripts.d.ts.map +1 -0
  78. package/dist/core/ralph-scripts.js +49 -0
  79. package/dist/core/ralph-scripts.js.map +1 -0
  80. package/dist/core/review-manager.d.ts +74 -0
  81. package/dist/core/review-manager.d.ts.map +1 -0
  82. package/dist/core/review-manager.js +371 -0
  83. package/dist/core/review-manager.js.map +1 -0
  84. package/dist/index.js +94 -2
  85. package/dist/index.js.map +1 -1
  86. package/dist/mcp/rulebook-server.d.ts.map +1 -1
  87. package/dist/mcp/rulebook-server.js +9 -2
  88. package/dist/mcp/rulebook-server.js.map +1 -1
  89. package/dist/memory/memory-store.d.ts.map +1 -1
  90. package/dist/memory/memory-store.js +4 -0
  91. package/dist/memory/memory-store.js.map +1 -1
  92. package/dist/types.d.ts +55 -2
  93. package/dist/types.d.ts.map +1 -1
  94. package/package.json +1 -1
  95. package/templates/agents/implementer.md +35 -0
  96. package/templates/agents/researcher.md +34 -0
  97. package/templates/agents/team-lead.md +34 -0
  98. package/templates/agents/tester.md +42 -0
  99. package/templates/ci/rulebook-review.yml +26 -0
  100. package/templates/core/AGENTS_LEAN.md +25 -0
  101. package/templates/core/AGENTS_OVERRIDE.md +16 -0
  102. package/templates/core/MULTI_AGENT.md +74 -0
  103. package/templates/core/PLANS.md +28 -0
  104. package/templates/core/RALPH.md +45 -4
  105. package/templates/ides/CONTINUE_RULES.md +16 -0
  106. package/templates/ides/COPILOT_INSTRUCTIONS.md +23 -0
  107. package/templates/ides/GEMINI_RULES.md +17 -0
  108. package/templates/ides/WINDSURF_RULES.md +14 -0
  109. package/templates/ides/cursor-mdc/go.mdc +24 -0
  110. package/templates/ides/cursor-mdc/python.mdc +24 -0
  111. package/templates/ides/cursor-mdc/quality.mdc +25 -0
  112. package/templates/ides/cursor-mdc/ralph.mdc +39 -0
  113. package/templates/ides/cursor-mdc/rulebook.mdc +38 -0
  114. package/templates/ides/cursor-mdc/rust.mdc +24 -0
  115. package/templates/ides/cursor-mdc/typescript.mdc +25 -0
  116. package/templates/modules/sequential-thinking.md +42 -0
  117. package/templates/ralph/ralph-history.bat +4 -0
  118. package/templates/ralph/ralph-history.sh +5 -0
  119. package/templates/ralph/ralph-init.bat +5 -0
  120. package/templates/ralph/ralph-init.sh +5 -0
  121. package/templates/ralph/ralph-pause.bat +5 -0
  122. package/templates/ralph/ralph-pause.sh +5 -0
  123. package/templates/ralph/ralph-run.bat +5 -0
  124. package/templates/ralph/ralph-run.sh +5 -0
  125. package/templates/ralph/ralph-status.bat +4 -0
  126. package/templates/ralph/ralph-status.sh +5 -0
  127. package/templates/services/DATADOG.md +26 -0
  128. package/templates/services/DOCKER.md +124 -0
  129. package/templates/services/DOCKER_COMPOSE.md +168 -0
  130. package/templates/services/HELM.md +194 -0
  131. package/templates/services/KUBERNETES.md +208 -0
  132. package/templates/services/OPENTELEMETRY.md +25 -0
  133. package/templates/services/PINO.md +24 -0
  134. package/templates/services/PROMETHEUS.md +33 -0
  135. package/templates/services/SENTRY.md +23 -0
  136. package/templates/services/WINSTON.md +30 -0
  137. package/dist/core/openspec-manager.d.ts +0 -133
  138. package/dist/core/openspec-manager.d.ts.map +0 -1
  139. package/dist/core/openspec-manager.js +0 -596
  140. package/dist/core/openspec-manager.js.map +0 -1
  141. package/dist/core/openspec-migrator.d.ts +0 -27
  142. package/dist/core/openspec-migrator.d.ts.map +0 -1
  143. package/dist/core/openspec-migrator.js +0 -262
  144. package/dist/core/openspec-migrator.js.map +0 -1
  145. package/dist/core/test-task-manager.d.ts +0 -49
  146. package/dist/core/test-task-manager.d.ts.map +0 -1
  147. package/dist/core/test-task-manager.js +0 -121
  148. package/dist/core/test-task-manager.js.map +0 -1
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Multi-Tool Config Generator
3
+ *
4
+ * Generates IDE/AI-tool configuration files for detected tools:
5
+ * - GEMINI.md for Gemini CLI
6
+ * - .continue/rules/RULEBOOK.md for Continue.dev
7
+ * - .windsurfrules for Windsurf IDE
8
+ * - .github/copilot-instructions.md for GitHub Copilot
9
+ *
10
+ * Each generator is idempotent: if the file already contains the
11
+ * RULEBOOK marker it gets updated; if it exists without the marker
12
+ * (user-owned file) it is skipped.
13
+ */
14
+ import path from 'path';
15
+ import { existsSync } from 'fs';
16
+ import { readFile, writeFile, mkdir } from 'fs/promises';
17
+ import { fileURLToPath } from 'url';
18
+ import { dirname } from 'path';
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = dirname(__filename);
21
+ /** Marker used to identify rulebook-managed content in generated files. */
22
+ const RULEBOOK_MARKER = '<!-- RULEBOOK:START -->';
23
+ /**
24
+ * Resolve the templates/ides/ directory relative to the compiled dist/ output.
25
+ * Uses the same __dirname strategy as cursor-mdc-generator.ts.
26
+ */
27
+ function getTemplatesDir() {
28
+ return path.join(__dirname, '..', '..', 'templates', 'ides');
29
+ }
30
+ /**
31
+ * Read a template file from templates/ides/.
32
+ * Returns the template content or null if the template does not exist.
33
+ */
34
+ async function readTemplate(templateName) {
35
+ const templatePath = path.join(getTemplatesDir(), templateName);
36
+ if (!existsSync(templatePath)) {
37
+ return null;
38
+ }
39
+ return readFile(templatePath, 'utf-8');
40
+ }
41
+ /**
42
+ * Write content to a destination file following the idempotent pattern:
43
+ * - If the file does not exist, create it with the template content.
44
+ * - If the file exists and contains the RULEBOOK marker, update it.
45
+ * - If the file exists without the marker (user-owned), skip and return null.
46
+ *
47
+ * Returns the absolute path written, or null if skipped.
48
+ */
49
+ async function writeIdempotent(destPath, content) {
50
+ if (existsSync(destPath)) {
51
+ const existing = await readFile(destPath, 'utf-8');
52
+ if (!existing.includes(RULEBOOK_MARKER)) {
53
+ // User-owned file — do not overwrite
54
+ return null;
55
+ }
56
+ }
57
+ // Ensure the parent directory exists
58
+ const parentDir = path.dirname(destPath);
59
+ if (!existsSync(parentDir)) {
60
+ await mkdir(parentDir, { recursive: true });
61
+ }
62
+ await writeFile(destPath, content, 'utf-8');
63
+ return destPath;
64
+ }
65
+ /**
66
+ * Generate GEMINI.md in the project root for Gemini CLI.
67
+ *
68
+ * @param projectRoot - Absolute path to the project root.
69
+ * @returns The path written, or null if skipped.
70
+ */
71
+ export async function generateGeminiMd(projectRoot) {
72
+ const template = await readTemplate('GEMINI_RULES.md');
73
+ if (!template) {
74
+ return null;
75
+ }
76
+ const destPath = path.join(projectRoot, 'GEMINI.md');
77
+ return writeIdempotent(destPath, template);
78
+ }
79
+ /**
80
+ * Generate .continue/rules/RULEBOOK.md for the Continue.dev IDE extension.
81
+ *
82
+ * @param projectRoot - Absolute path to the project root.
83
+ * @returns The path written, or null if skipped.
84
+ */
85
+ export async function generateContinueRules(projectRoot) {
86
+ const template = await readTemplate('CONTINUE_RULES.md');
87
+ if (!template) {
88
+ return null;
89
+ }
90
+ const destPath = path.join(projectRoot, '.continue', 'rules', 'RULEBOOK.md');
91
+ return writeIdempotent(destPath, template);
92
+ }
93
+ /**
94
+ * Generate .windsurfrules in the project root for Windsurf IDE.
95
+ *
96
+ * @param projectRoot - Absolute path to the project root.
97
+ * @returns The path written, or null if skipped.
98
+ */
99
+ export async function generateWindsurfRules(projectRoot) {
100
+ const template = await readTemplate('WINDSURF_RULES.md');
101
+ if (!template) {
102
+ return null;
103
+ }
104
+ const destPath = path.join(projectRoot, '.windsurfrules');
105
+ return writeIdempotent(destPath, template);
106
+ }
107
+ /**
108
+ * Generate .github/copilot-instructions.md for GitHub Copilot.
109
+ *
110
+ * @param projectRoot - Absolute path to the project root.
111
+ * @returns The path written, or null if skipped.
112
+ */
113
+ export async function generateCopilotInstructions(projectRoot) {
114
+ const template = await readTemplate('COPILOT_INSTRUCTIONS.md');
115
+ if (!template) {
116
+ return null;
117
+ }
118
+ const destPath = path.join(projectRoot, '.github', 'copilot-instructions.md');
119
+ return writeIdempotent(destPath, template);
120
+ }
121
+ /**
122
+ * Generate configuration files for all detected AI tools.
123
+ * Only generates files for tools that are actually detected in the project.
124
+ *
125
+ * @param projectRoot - Absolute path to the project root.
126
+ * @param detection - The project detection result containing tool detection flags.
127
+ * @returns An object with paths of all generated files (undefined for skipped tools).
128
+ */
129
+ export async function generateMultiToolConfigs(projectRoot, detection) {
130
+ const result = {};
131
+ if (detection.geminiCli?.detected) {
132
+ const written = await generateGeminiMd(projectRoot);
133
+ if (written) {
134
+ result.geminiMd = written;
135
+ }
136
+ }
137
+ if (detection.continueDev?.detected) {
138
+ const written = await generateContinueRules(projectRoot);
139
+ if (written) {
140
+ result.continueRules = written;
141
+ }
142
+ }
143
+ if (detection.windsurf?.detected) {
144
+ const written = await generateWindsurfRules(projectRoot);
145
+ if (written) {
146
+ result.windsurfRules = written;
147
+ }
148
+ }
149
+ if (detection.githubCopilot?.detected) {
150
+ const written = await generateCopilotInstructions(projectRoot);
151
+ if (written) {
152
+ result.copilotInstructions = written;
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ //# sourceMappingURL=multi-tool-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-tool-generator.js","sourceRoot":"","sources":["../../src/core/multi-tool-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Get path to AGENTS.override.md in the project root.
3
+ */
4
+ export declare function getOverridePath(projectRoot: string): string;
5
+ /**
6
+ * Check if AGENTS.override.md exists.
7
+ */
8
+ export declare function overrideExists(projectRoot: string): boolean;
9
+ /**
10
+ * Read override content, stripping OVERRIDE:START/END markers.
11
+ * Returns empty string if file does not exist or has no custom content.
12
+ */
13
+ export declare function readOverrideContent(projectRoot: string): Promise<string>;
14
+ /**
15
+ * Create AGENTS.override.md from template if it does not already exist.
16
+ * Returns true if file was created, false if it already existed.
17
+ */
18
+ export declare function initOverride(projectRoot: string): Promise<boolean>;
19
+ /**
20
+ * Clear AGENTS.override.md back to the empty template.
21
+ */
22
+ export declare function clearOverride(projectRoot: string): Promise<void>;
23
+ //# sourceMappingURL=override-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"override-manager.d.ts","sourceRoot":"","sources":["../../src/core/override-manager.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB9E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA4BxE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtE"}
@@ -0,0 +1,82 @@
1
+ import { existsSync } from 'fs';
2
+ import { readFile, writeFile } from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileExists } from '../utils/file-system.js';
5
+ const OVERRIDE_FILE = 'AGENTS.override.md';
6
+ /**
7
+ * Get path to AGENTS.override.md in the project root.
8
+ */
9
+ export function getOverridePath(projectRoot) {
10
+ return path.join(projectRoot, OVERRIDE_FILE);
11
+ }
12
+ /**
13
+ * Check if AGENTS.override.md exists.
14
+ */
15
+ export function overrideExists(projectRoot) {
16
+ return existsSync(getOverridePath(projectRoot));
17
+ }
18
+ /**
19
+ * Read override content, stripping OVERRIDE:START/END markers.
20
+ * Returns empty string if file does not exist or has no custom content.
21
+ */
22
+ export async function readOverrideContent(projectRoot) {
23
+ const overridePath = getOverridePath(projectRoot);
24
+ if (!existsSync(overridePath))
25
+ return '';
26
+ const raw = await readFile(overridePath, 'utf-8');
27
+ // Strip marker comments — return only actual content between them
28
+ const match = raw.match(/<!-- OVERRIDE:START -->([\s\S]*?)<!-- OVERRIDE:END -->/);
29
+ if (!match)
30
+ return raw.trim();
31
+ const content = match[1].trim();
32
+ // If it still contains only the template placeholder text, treat as empty
33
+ if (content.includes('This file contains project-specific directives') &&
34
+ !content.split('\n').some((line) => line.startsWith('- ') && !line.includes('**Example'))) {
35
+ return '';
36
+ }
37
+ return content;
38
+ }
39
+ /**
40
+ * Create AGENTS.override.md from template if it does not already exist.
41
+ * Returns true if file was created, false if it already existed.
42
+ */
43
+ export async function initOverride(projectRoot) {
44
+ const overridePath = getOverridePath(projectRoot);
45
+ if (existsSync(overridePath))
46
+ return false;
47
+ const templatePath = path.join(path.dirname(path.dirname(new URL(import.meta.url).pathname)), 'templates', 'core', 'AGENTS_OVERRIDE.md');
48
+ let templateContent = '';
49
+ if (await fileExists(templatePath)) {
50
+ templateContent = await readFile(templatePath, 'utf-8');
51
+ }
52
+ else {
53
+ templateContent = [
54
+ '<!-- OVERRIDE:START -->',
55
+ '# Project-Specific Overrides',
56
+ '',
57
+ 'Add your custom rules and team conventions here.',
58
+ 'This file is never overwritten by `rulebook init` or `rulebook update`.',
59
+ '<!-- OVERRIDE:END -->',
60
+ '',
61
+ ].join('\n');
62
+ }
63
+ await writeFile(overridePath, templateContent);
64
+ return true;
65
+ }
66
+ /**
67
+ * Clear AGENTS.override.md back to the empty template.
68
+ */
69
+ export async function clearOverride(projectRoot) {
70
+ const overridePath = getOverridePath(projectRoot);
71
+ const emptyContent = [
72
+ '<!-- OVERRIDE:START -->',
73
+ '# Project-Specific Overrides',
74
+ '',
75
+ 'Add your custom rules and team conventions here.',
76
+ 'This file is never overwritten by `rulebook init` or `rulebook update`.',
77
+ '<!-- OVERRIDE:END -->',
78
+ '',
79
+ ].join('\n');
80
+ await writeFile(overridePath, emptyContent);
81
+ }
82
+ //# sourceMappingURL=override-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"override-manager.js","sourceRoot":"","sources":["../../src/core/override-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Plans Manager — PLANS.md Session Scratchpad
3
+ *
4
+ * Provides AI session continuity via a persistent scratchpad file.
5
+ * AI agents read PLANS.md at session start and update it during/after work.
6
+ */
7
+ export interface PlansContent {
8
+ context: string;
9
+ currentTask: string;
10
+ history: string;
11
+ raw: string;
12
+ }
13
+ /**
14
+ * Get the path to PLANS.md inside the .rulebook directory.
15
+ */
16
+ export declare function getPlansPath(projectRoot: string): string;
17
+ /**
18
+ * Check if PLANS.md exists.
19
+ */
20
+ export declare function plansExists(projectRoot: string): boolean;
21
+ /**
22
+ * Read and parse PLANS.md sections.
23
+ * Returns null if file does not exist.
24
+ */
25
+ export declare function readPlans(projectRoot: string): Promise<PlansContent | null>;
26
+ /**
27
+ * Create PLANS.md from template if it does not exist.
28
+ */
29
+ export declare function initPlans(projectRoot: string): Promise<boolean>;
30
+ /**
31
+ * Update the Active Context section of PLANS.md.
32
+ */
33
+ export declare function updatePlansContext(projectRoot: string, context: string): Promise<void>;
34
+ /**
35
+ * Update the Current Task section of PLANS.md.
36
+ */
37
+ export declare function updatePlansTask(projectRoot: string, task: string): Promise<void>;
38
+ /**
39
+ * Append an entry to the Session History section of PLANS.md.
40
+ */
41
+ export declare function appendPlansHistory(projectRoot: string, entry: string): Promise<void>;
42
+ /**
43
+ * Reset PLANS.md to the template (clear context, task, and history).
44
+ */
45
+ export declare function clearPlans(projectRoot: string): Promise<void>;
46
+ //# sourceMappingURL=plans-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans-manager.d.ts","sourceRoot":"","sources":["../../src/core/plans-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAcjF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUrE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5F;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY1F;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnE"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Plans Manager — PLANS.md Session Scratchpad
3
+ *
4
+ * Provides AI session continuity via a persistent scratchpad file.
5
+ * AI agents read PLANS.md at session start and update it during/after work.
6
+ */
7
+ import { join, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { existsSync } from 'fs';
10
+ import { readFile, writeFile, mkdir } from 'fs/promises';
11
+ const PLANS_FILE = 'PLANS.md';
12
+ const CONTEXT_START = '<!-- PLANS:CONTEXT:START -->';
13
+ const CONTEXT_END = '<!-- PLANS:CONTEXT:END -->';
14
+ const TASK_START = '<!-- PLANS:TASK:START -->';
15
+ const TASK_END = '<!-- PLANS:TASK:END -->';
16
+ const HISTORY_START = '<!-- PLANS:HISTORY:START -->';
17
+ const HISTORY_END = '<!-- PLANS:HISTORY:END -->';
18
+ /**
19
+ * Get the path to PLANS.md inside the .rulebook directory.
20
+ */
21
+ export function getPlansPath(projectRoot) {
22
+ return join(projectRoot, '.rulebook', PLANS_FILE);
23
+ }
24
+ /**
25
+ * Check if PLANS.md exists.
26
+ */
27
+ export function plansExists(projectRoot) {
28
+ return existsSync(getPlansPath(projectRoot));
29
+ }
30
+ /**
31
+ * Read and parse PLANS.md sections.
32
+ * Returns null if file does not exist.
33
+ */
34
+ export async function readPlans(projectRoot) {
35
+ const plansPath = getPlansPath(projectRoot);
36
+ if (!existsSync(plansPath)) {
37
+ return null;
38
+ }
39
+ const raw = await readFile(plansPath, 'utf-8');
40
+ return {
41
+ context: extractSection(raw, CONTEXT_START, CONTEXT_END),
42
+ currentTask: extractSection(raw, TASK_START, TASK_END),
43
+ history: extractSection(raw, HISTORY_START, HISTORY_END),
44
+ raw,
45
+ };
46
+ }
47
+ /**
48
+ * Create PLANS.md from template if it does not exist.
49
+ */
50
+ export async function initPlans(projectRoot) {
51
+ const plansPath = getPlansPath(projectRoot);
52
+ if (existsSync(plansPath)) {
53
+ return false; // Already exists
54
+ }
55
+ await mkdir(join(projectRoot, '.rulebook'), { recursive: true });
56
+ const template = await loadTemplate();
57
+ await writeFile(plansPath, template, 'utf-8');
58
+ return true;
59
+ }
60
+ /**
61
+ * Update the Active Context section of PLANS.md.
62
+ */
63
+ export async function updatePlansContext(projectRoot, context) {
64
+ const plansPath = getPlansPath(projectRoot);
65
+ await mkdir(join(projectRoot, '.rulebook'), { recursive: true });
66
+ let content = existsSync(plansPath) ? await readFile(plansPath, 'utf-8') : await loadTemplate();
67
+ content = replaceSection(content, CONTEXT_START, CONTEXT_END, context);
68
+ await writeFile(plansPath, content, 'utf-8');
69
+ }
70
+ /**
71
+ * Update the Current Task section of PLANS.md.
72
+ */
73
+ export async function updatePlansTask(projectRoot, task) {
74
+ const plansPath = getPlansPath(projectRoot);
75
+ await mkdir(join(projectRoot, '.rulebook'), { recursive: true });
76
+ let content = existsSync(plansPath) ? await readFile(plansPath, 'utf-8') : await loadTemplate();
77
+ content = replaceSection(content, TASK_START, TASK_END, task);
78
+ await writeFile(plansPath, content, 'utf-8');
79
+ }
80
+ /**
81
+ * Append an entry to the Session History section of PLANS.md.
82
+ */
83
+ export async function appendPlansHistory(projectRoot, entry) {
84
+ const plansPath = getPlansPath(projectRoot);
85
+ await mkdir(join(projectRoot, '.rulebook'), { recursive: true });
86
+ let content = existsSync(plansPath) ? await readFile(plansPath, 'utf-8') : await loadTemplate();
87
+ const existing = extractSection(content, HISTORY_START, HISTORY_END);
88
+ const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 16);
89
+ const newEntry = `\n### ${timestamp}\n${entry}`;
90
+ const updated = existing.trim() ? existing + '\n' + newEntry : newEntry;
91
+ content = replaceSection(content, HISTORY_START, HISTORY_END, updated);
92
+ await writeFile(plansPath, content, 'utf-8');
93
+ }
94
+ /**
95
+ * Reset PLANS.md to the template (clear context, task, and history).
96
+ */
97
+ export async function clearPlans(projectRoot) {
98
+ const plansPath = getPlansPath(projectRoot);
99
+ const template = await loadTemplate();
100
+ await mkdir(join(projectRoot, '.rulebook'), { recursive: true });
101
+ await writeFile(plansPath, template, 'utf-8');
102
+ }
103
+ // ─── Helpers ───────────────────────────────────────────────────────────────
104
+ function extractSection(content, startMarker, endMarker) {
105
+ const startIdx = content.indexOf(startMarker);
106
+ const endIdx = content.indexOf(endMarker);
107
+ if (startIdx === -1 || endIdx === -1)
108
+ return '';
109
+ return content.slice(startIdx + startMarker.length, endIdx).trim();
110
+ }
111
+ function replaceSection(content, startMarker, endMarker, newValue) {
112
+ const startIdx = content.indexOf(startMarker);
113
+ const endIdx = content.indexOf(endMarker);
114
+ if (startIdx === -1 || endIdx === -1)
115
+ return content;
116
+ const before = content.slice(0, startIdx + startMarker.length);
117
+ const after = content.slice(endIdx);
118
+ return `${before}\n${newValue}\n${after}`;
119
+ }
120
+ async function loadTemplate() {
121
+ // Try to load from bundled templates
122
+ try {
123
+ const __filename = fileURLToPath(import.meta.url);
124
+ const __dirname = dirname(__filename);
125
+ const templatePath = join(__dirname, '..', '..', 'templates', 'core', 'PLANS.md');
126
+ if (existsSync(templatePath)) {
127
+ return readFile(templatePath, 'utf-8');
128
+ }
129
+ }
130
+ catch {
131
+ // Fall through to inline template
132
+ }
133
+ // Inline fallback template
134
+ return `<!-- PLANS:START -->
135
+ # Project Plans & Session Context
136
+
137
+ This file is a **persistent session scratchpad** maintained by AI agents.
138
+ It provides continuity across sessions without relying on conversation history.
139
+
140
+ ## Active Context
141
+
142
+ <!-- PLANS:CONTEXT:START -->
143
+ _No active context. Start a session to populate this section._
144
+ <!-- PLANS:CONTEXT:END -->
145
+
146
+ ## Current Task
147
+
148
+ <!-- PLANS:TASK:START -->
149
+ _No task in progress._
150
+ <!-- PLANS:TASK:END -->
151
+
152
+ ## Session History
153
+
154
+ <!-- PLANS:HISTORY:START -->
155
+ <!-- PLANS:HISTORY:END -->
156
+ `;
157
+ }
158
+ //# sourceMappingURL=plans-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans-manager.js","sourceRoot":"","sources":["../../src/core/plans-manager.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,18 @@ export declare class PRDGenerator {
20
20
  * Uses the full rulebook task structure: proposal.md + tasks.md + specs/
21
21
  */
22
22
  private convertTaskToUserStory;
23
+ /**
24
+ * Load SHALL/MUST requirements from specs/*.md files as acceptance criteria.
25
+ */
26
+ private loadSpecCriteria;
27
+ /**
28
+ * Extract SHALL/MUST statements from spec content as acceptance criteria.
29
+ */
30
+ private extractShallMust;
31
+ /**
32
+ * List relative paths of spec files for notes/traceability.
33
+ */
34
+ private listSpecFiles;
23
35
  /**
24
36
  * Load tasks checklist from tasks.md
25
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"prd-generator.d.ts","sourceRoot":"","sources":["../../src/core/prd-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAgB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAErD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA0B;IAKrF;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAwBzD;;OAEG;YACW,iBAAiB;IAyC/B;;;OAGG;YACW,sBAAsB;IAkBpC;;OAEG;YACW,kBAAkB;IA0BhC;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAY3B"}
1
+ {"version":3,"file":"prd-generator.d.ts","sourceRoot":"","sources":["../../src/core/prd-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAgB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAErD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA0B;IAKrF;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAwBzD;;OAEG;YACW,iBAAiB;IAyC/B;;;OAGG;YACW,sBAAsB;IA0BpC;;OAEG;YACW,gBAAgB;IAmC9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;YACW,aAAa;IA6B3B;;OAEG;YACW,kBAAkB;IA0BhC;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAY3B"}
@@ -77,17 +77,106 @@ export class PRDGenerator {
77
77
  const title = this.extractTitle(task.proposal);
78
78
  const description = this.extractDescription(task.proposal);
79
79
  const tasksChecklist = await this.loadTasksChecklist(task.path);
80
+ const specCriteria = await this.loadSpecCriteria(task.path);
81
+ // Merge checklist items with SHALL/MUST requirements from specs
82
+ const allCriteria = [...tasksChecklist, ...specCriteria];
83
+ // Build notes: include spec file references for traceability
84
+ const specSources = await this.listSpecFiles(task.path);
85
+ const notes = specSources.length > 0 ? `Spec files: ${specSources.join(', ')}` : '';
80
86
  return {
81
87
  id: `US-${String(priority).padStart(3, '0')}`,
82
88
  title: title || task.id,
83
89
  description: description || 'Task extracted from rulebook proposal',
84
- acceptanceCriteria: tasksChecklist.length > 0 ? tasksChecklist.slice(0, 10) : ['Implementation complete'],
90
+ acceptanceCriteria: allCriteria.length > 0 ? allCriteria.slice(0, 15) : ['Implementation complete'],
85
91
  priority,
86
92
  passes: false,
87
- notes: '',
93
+ notes,
88
94
  sourceTaskId: task.id,
89
95
  };
90
96
  }
97
+ /**
98
+ * Load SHALL/MUST requirements from specs/*.md files as acceptance criteria.
99
+ */
100
+ async loadSpecCriteria(taskPath) {
101
+ const specsDir = path.join(taskPath, 'specs');
102
+ if (!existsSync(specsDir)) {
103
+ return [];
104
+ }
105
+ const criteria = [];
106
+ try {
107
+ const entries = await readdir(specsDir, { withFileTypes: true });
108
+ for (const entry of entries) {
109
+ const entryPath = path.join(specsDir, entry.name);
110
+ if (entry.isDirectory()) {
111
+ // Recurse one level: specs/<module>/spec.md
112
+ const subEntries = await readdir(entryPath, { withFileTypes: true });
113
+ for (const sub of subEntries) {
114
+ if (sub.isFile() && sub.name.endsWith('.md')) {
115
+ const content = await readFile(path.join(entryPath, sub.name), 'utf-8');
116
+ this.extractShallMust(content, criteria);
117
+ }
118
+ }
119
+ }
120
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
121
+ const content = await readFile(entryPath, 'utf-8');
122
+ this.extractShallMust(content, criteria);
123
+ }
124
+ }
125
+ }
126
+ catch (err) {
127
+ this.logger.warn(`Failed to read spec files for task at ${taskPath}: ${err}`);
128
+ }
129
+ return criteria;
130
+ }
131
+ /**
132
+ * Extract SHALL/MUST statements from spec content as acceptance criteria.
133
+ */
134
+ extractShallMust(content, criteria) {
135
+ const lines = content.split('\n');
136
+ for (const line of lines) {
137
+ const trimmed = line.trim();
138
+ // Match lines with SHALL or MUST (requirement language)
139
+ if (/\b(SHALL|MUST)\b/.test(trimmed) && trimmed.length > 10 && trimmed.length < 300) {
140
+ // Clean up markdown: remove leading dashes, asterisks, backtick code
141
+ const cleaned = trimmed.replace(/^[-*]\s+/, '').replace(/`[^`]+`/g, (m) => m.slice(1, -1));
142
+ if (!criteria.includes(cleaned)) {
143
+ criteria.push(cleaned);
144
+ }
145
+ }
146
+ }
147
+ }
148
+ /**
149
+ * List relative paths of spec files for notes/traceability.
150
+ */
151
+ async listSpecFiles(taskPath) {
152
+ const specsDir = path.join(taskPath, 'specs');
153
+ if (!existsSync(specsDir)) {
154
+ return [];
155
+ }
156
+ const files = [];
157
+ try {
158
+ const entries = await readdir(specsDir, { withFileTypes: true });
159
+ for (const entry of entries) {
160
+ if (entry.isDirectory()) {
161
+ const subEntries = await readdir(path.join(specsDir, entry.name), {
162
+ withFileTypes: true,
163
+ });
164
+ for (const sub of subEntries) {
165
+ if (sub.isFile() && sub.name.endsWith('.md')) {
166
+ files.push(`specs/${entry.name}/${sub.name}`);
167
+ }
168
+ }
169
+ }
170
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
171
+ files.push(`specs/${entry.name}`);
172
+ }
173
+ }
174
+ }
175
+ catch {
176
+ // ignore
177
+ }
178
+ return files;
179
+ }
91
180
  /**
92
181
  * Load tasks checklist from tasks.md
93
182
  */