@hivehub/rulebook 5.5.2 → 5.7.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.
- package/.claude/commands/rulebook-learn-capture.md +41 -48
- package/.claude/commands/rulebook-learn-list.md +13 -13
- package/README.md +332 -394
- package/dist/cli/commands/context-intelligence.d.ts +0 -1
- package/dist/cli/commands/context-intelligence.d.ts.map +1 -1
- package/dist/cli/commands/context-intelligence.js +12 -33
- package/dist/cli/commands/context-intelligence.js.map +1 -1
- package/dist/cli/commands/index.d.ts +4 -7
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +4 -7
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +40 -81
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts +0 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +1 -7
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/memory.d.ts +7 -1
- package/dist/cli/commands/memory.d.ts.map +1 -1
- package/dist/cli/commands/memory.js +51 -57
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/misc.d.ts +1 -15
- package/dist/cli/commands/misc.d.ts.map +1 -1
- package/dist/cli/commands/misc.js +36 -215
- package/dist/cli/commands/misc.js.map +1 -1
- package/dist/cli/commands/plans.d.ts +0 -6
- package/dist/cli/commands/plans.d.ts.map +1 -1
- package/dist/cli/commands/plans.js +9 -77
- package/dist/cli/commands/plans.js.map +1 -1
- package/dist/cli/commands/skills.js +6 -6
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/task.js +4 -4
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +122 -52
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/prompts.d.ts.map +1 -1
- package/dist/cli/prompts.js +1 -78
- package/dist/cli/prompts.js.map +1 -1
- package/dist/core/claude/claude-mcp.d.ts +59 -0
- package/dist/core/claude/claude-mcp.d.ts.map +1 -0
- package/dist/core/claude/claude-mcp.js +220 -0
- package/dist/core/claude/claude-mcp.js.map +1 -0
- package/dist/core/claude/claude-md-generator.d.ts +52 -0
- package/dist/core/claude/claude-md-generator.d.ts.map +1 -0
- package/dist/core/claude/claude-md-generator.js +104 -0
- package/dist/core/claude/claude-md-generator.js.map +1 -0
- package/dist/core/claude/claude-settings-manager.d.ts +44 -0
- package/dist/core/claude/claude-settings-manager.d.ts.map +1 -0
- package/dist/core/claude/claude-settings-manager.js +194 -0
- package/dist/core/claude/claude-settings-manager.js.map +1 -0
- package/dist/core/console/cli-bridge.d.ts +113 -0
- package/dist/core/console/cli-bridge.d.ts.map +1 -0
- package/dist/core/console/cli-bridge.js +1094 -0
- package/dist/core/console/cli-bridge.js.map +1 -0
- package/dist/core/detect/detector.d.ts +35 -0
- package/dist/core/detect/detector.d.ts.map +1 -0
- package/dist/core/detect/detector.js +541 -0
- package/dist/core/detect/detector.js.map +1 -0
- package/dist/core/docs/docs-generator.d.ts +9 -0
- package/dist/core/docs/docs-generator.d.ts.map +1 -0
- package/dist/core/docs/docs-generator.js +531 -0
- package/dist/core/docs/docs-generator.js.map +1 -0
- package/dist/core/docs/mcp-reference-generator.d.ts +13 -0
- package/dist/core/docs/mcp-reference-generator.d.ts.map +1 -0
- package/dist/core/docs/mcp-reference-generator.js +66 -0
- package/dist/core/docs/mcp-reference-generator.js.map +1 -0
- package/dist/core/generators/generator.d.ts +54 -0
- package/dist/core/generators/generator.d.ts.map +1 -0
- package/dist/core/generators/generator.js +1041 -0
- package/dist/core/generators/generator.js.map +1 -0
- package/dist/core/generators/gitignore-generator.d.ts +13 -0
- package/dist/core/generators/gitignore-generator.d.ts.map +1 -0
- package/dist/core/generators/gitignore-generator.js +307 -0
- package/dist/core/generators/gitignore-generator.js.map +1 -0
- package/dist/core/generators/minimal-scaffolder.d.ts +8 -0
- package/dist/core/generators/minimal-scaffolder.d.ts.map +1 -0
- package/dist/core/generators/minimal-scaffolder.js +51 -0
- package/dist/core/generators/minimal-scaffolder.js.map +1 -0
- package/dist/core/generators/rules-generator.d.ts +73 -0
- package/dist/core/generators/rules-generator.d.ts.map +1 -0
- package/dist/core/generators/rules-generator.js +202 -0
- package/dist/core/generators/rules-generator.js.map +1 -0
- package/dist/core/generators/workflow-generator.d.ts +15 -0
- package/dist/core/generators/workflow-generator.d.ts.map +1 -0
- package/dist/core/generators/workflow-generator.js +390 -0
- package/dist/core/generators/workflow-generator.js.map +1 -0
- package/dist/core/ide/multi-tool-generator.d.ts +59 -0
- package/dist/core/ide/multi-tool-generator.d.ts.map +1 -0
- package/dist/core/ide/multi-tool-generator.js +157 -0
- package/dist/core/ide/multi-tool-generator.js.map +1 -0
- package/dist/core/ide/opencode-generator.d.ts +72 -0
- package/dist/core/ide/opencode-generator.d.ts.map +1 -0
- package/dist/core/ide/opencode-generator.js +450 -0
- package/dist/core/ide/opencode-generator.js.map +1 -0
- package/dist/core/merger.d.ts +1 -1
- package/dist/core/merger.d.ts.map +1 -1
- package/dist/core/merger.js +5 -5
- package/dist/core/merger.js.map +1 -1
- package/dist/core/migrator.d.ts +0 -1
- package/dist/core/migrator.d.ts.map +1 -1
- package/dist/core/migrator.js +4 -29
- package/dist/core/migrator.js.map +1 -1
- package/dist/core/quality/coverage-checker.d.ts +14 -0
- package/dist/core/quality/coverage-checker.d.ts.map +1 -0
- package/dist/core/quality/coverage-checker.js +176 -0
- package/dist/core/quality/coverage-checker.js.map +1 -0
- package/dist/core/quality/dependency-checker.d.ts +21 -0
- package/dist/core/quality/dependency-checker.d.ts.map +1 -0
- package/dist/core/quality/dependency-checker.js +247 -0
- package/dist/core/quality/dependency-checker.js.map +1 -0
- package/dist/core/quality/doctor.d.ts +19 -0
- package/dist/core/quality/doctor.d.ts.map +1 -0
- package/dist/core/quality/doctor.js +163 -0
- package/dist/core/quality/doctor.js.map +1 -0
- package/dist/core/quality/validator.d.ts +21 -0
- package/dist/core/quality/validator.d.ts.map +1 -0
- package/dist/core/quality/validator.js +177 -0
- package/dist/core/quality/validator.js.map +1 -0
- package/dist/core/skills/skills-manager.d.ts +126 -0
- package/dist/core/skills/skills-manager.d.ts.map +1 -0
- package/dist/core/skills/skills-manager.js +630 -0
- package/dist/core/skills/skills-manager.js.map +1 -0
- package/dist/core/state/config-manager.d.ts +86 -0
- package/dist/core/state/config-manager.d.ts.map +1 -0
- package/dist/core/state/config-manager.js +562 -0
- package/dist/core/state/config-manager.js.map +1 -0
- package/dist/core/state/override-manager.d.ts +23 -0
- package/dist/core/state/override-manager.d.ts.map +1 -0
- package/dist/core/state/override-manager.js +82 -0
- package/dist/core/state/override-manager.js.map +1 -0
- package/dist/core/state/state-writer.d.ts +34 -0
- package/dist/core/state/state-writer.d.ts.map +1 -0
- package/dist/core/state/state-writer.js +78 -0
- package/dist/core/state/state-writer.js.map +1 -0
- package/dist/core/state/version-bumper.d.ts +19 -0
- package/dist/core/state/version-bumper.d.ts.map +1 -0
- package/dist/core/state/version-bumper.js +180 -0
- package/dist/core/state/version-bumper.js.map +1 -0
- package/dist/core/tasks/decision-manager.d.ts +25 -0
- package/dist/core/tasks/decision-manager.d.ts.map +1 -0
- package/dist/core/tasks/decision-manager.js +183 -0
- package/dist/core/tasks/decision-manager.js.map +1 -0
- package/dist/core/tasks/knowledge-manager.d.ts +24 -0
- package/dist/core/tasks/knowledge-manager.d.ts.map +1 -0
- package/dist/core/tasks/knowledge-manager.js +173 -0
- package/dist/core/tasks/knowledge-manager.js.map +1 -0
- package/dist/core/tasks/learn-manager.d.ts +27 -0
- package/dist/core/tasks/learn-manager.d.ts.map +1 -0
- package/dist/core/tasks/learn-manager.js +121 -0
- package/dist/core/tasks/learn-manager.js.map +1 -0
- package/dist/core/tasks/plans-manager.d.ts +46 -0
- package/dist/core/tasks/plans-manager.d.ts.map +1 -0
- package/dist/core/tasks/plans-manager.js +158 -0
- package/dist/core/tasks/plans-manager.js.map +1 -0
- package/dist/core/tasks/task-manager.d.ts +127 -0
- package/dist/core/tasks/task-manager.d.ts.map +1 -0
- package/dist/core/tasks/task-manager.js +607 -0
- package/dist/core/tasks/task-manager.js.map +1 -0
- package/dist/core/workspace/project-worker.d.ts +6 -6
- package/dist/core/workspace/project-worker.d.ts.map +1 -1
- package/dist/core/workspace/project-worker.js +6 -6
- package/dist/core/workspace/project-worker.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -176
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +16 -960
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/memory/file-search.d.ts +43 -0
- package/dist/memory/file-search.d.ts.map +1 -0
- package/dist/memory/file-search.js +228 -0
- package/dist/memory/file-search.js.map +1 -0
- package/dist/memory/file-store.d.ts +99 -0
- package/dist/memory/file-store.d.ts.map +1 -0
- package/dist/memory/file-store.js +615 -0
- package/dist/memory/file-store.js.map +1 -0
- package/dist/memory/legacy-migrator.d.ts +27 -0
- package/dist/memory/legacy-migrator.d.ts.map +1 -0
- package/dist/memory/legacy-migrator.js +185 -0
- package/dist/memory/legacy-migrator.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +25 -24
- package/dist/memory/memory-manager.d.ts.map +1 -1
- package/dist/memory/memory-manager.js +97 -140
- package/dist/memory/memory-manager.js.map +1 -1
- package/dist/memory/memory-types.d.ts +1 -1
- package/dist/memory/memory-types.d.ts.map +1 -1
- package/dist/types.d.ts +8 -119
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -6
- package/templates/agents/context-intelligence.md +50 -52
- package/templates/cli/OPENCODE.md +85 -18
- package/templates/commands/rulebook-learn-capture.md +41 -48
- package/templates/commands/rulebook-learn-list.md +13 -13
- package/templates/core/AGENTS_LEAN.md +0 -14
- package/templates/hooks/check-context-and-handoff.sh +8 -10
- package/templates/hooks/enforce-pre-tool.sh +70 -0
- package/templates/hooks/terse-mode-tracker.sh +146 -143
- package/templates/ides/OPENCODE.md +63 -0
- package/templates/skills/cli/opencode/SKILL.md +82 -28
- package/.claude/commands/ralph-config.md +0 -112
- package/.claude/commands/ralph-history.md +0 -110
- package/.claude/commands/ralph-init.md +0 -72
- package/.claude/commands/ralph-pause-resume.md +0 -105
- package/.claude/commands/ralph-run.md +0 -101
- package/.claude/commands/ralph-status.md +0 -76
- package/templates/core/RALPH.md +0 -471
- package/templates/frameworks/ANGULAR.md +0 -36
- package/templates/frameworks/DJANGO.md +0 -83
- package/templates/frameworks/ELECTRON.md +0 -147
- package/templates/frameworks/FLASK.md +0 -38
- package/templates/frameworks/FLUTTER.md +0 -55
- package/templates/frameworks/JQUERY.md +0 -32
- package/templates/frameworks/LARAVEL.md +0 -38
- package/templates/frameworks/NESTJS.md +0 -43
- package/templates/frameworks/NEXTJS.md +0 -127
- package/templates/frameworks/NUXT.md +0 -40
- package/templates/frameworks/RAILS.md +0 -66
- package/templates/frameworks/REACT.md +0 -38
- package/templates/frameworks/REACT_NATIVE.md +0 -47
- package/templates/frameworks/SPRING.md +0 -39
- package/templates/frameworks/SYMFONY.md +0 -36
- package/templates/frameworks/VUE.md +0 -36
- package/templates/frameworks/ZEND.md +0 -35
- package/templates/hooks/enforce-mcp-for-tasks.sh +0 -31
- package/templates/hooks/enforce-no-deferred.sh +0 -21
- package/templates/hooks/enforce-no-shortcuts.sh +0 -31
- package/templates/ides/COPILOT.md +0 -37
- package/templates/ides/CURSOR.md +0 -43
- package/templates/ides/JETBRAINS_AI.md +0 -35
- package/templates/ides/REPLIT.md +0 -36
- package/templates/ides/TABNINE.md +0 -29
- package/templates/ides/VSCODE.md +0 -40
- package/templates/ides/WINDSURF.md +0 -36
- package/templates/ides/ZED.md +0 -32
- package/templates/ides/cursor-mdc/go.mdc +0 -24
- package/templates/ides/cursor-mdc/python.mdc +0 -24
- package/templates/ides/cursor-mdc/quality.mdc +0 -25
- package/templates/ides/cursor-mdc/ralph.mdc +0 -39
- package/templates/ides/cursor-mdc/rulebook.mdc +0 -38
- package/templates/ides/cursor-mdc/rust.mdc +0 -24
- package/templates/ides/cursor-mdc/typescript.mdc +0 -25
- package/templates/ralph/ralph-history.bat +0 -4
- package/templates/ralph/ralph-history.sh +0 -5
- package/templates/ralph/ralph-init.bat +0 -5
- package/templates/ralph/ralph-init.sh +0 -5
- package/templates/ralph/ralph-pause.bat +0 -5
- package/templates/ralph/ralph-pause.sh +0 -5
- package/templates/ralph/ralph-run.bat +0 -5
- package/templates/ralph/ralph-run.sh +0 -5
- package/templates/ralph/ralph-status.bat +0 -4
- package/templates/ralph/ralph-status.sh +0 -5
- package/templates/services/AZURE_BLOB.md +0 -184
- package/templates/services/CASSANDRA.md +0 -239
- package/templates/services/DATADOG.md +0 -26
- package/templates/services/DOCKER.md +0 -124
- package/templates/services/DOCKER_COMPOSE.md +0 -168
- package/templates/services/DYNAMODB.md +0 -308
- package/templates/services/ELASTICSEARCH.md +0 -347
- package/templates/services/GCS.md +0 -178
- package/templates/services/HELM.md +0 -194
- package/templates/services/INFLUXDB.md +0 -265
- package/templates/services/KAFKA.md +0 -341
- package/templates/services/KUBERNETES.md +0 -208
- package/templates/services/MARIADB.md +0 -183
- package/templates/services/MEMCACHED.md +0 -242
- package/templates/services/MINIO.md +0 -201
- package/templates/services/MONGODB.md +0 -268
- package/templates/services/MYSQL.md +0 -358
- package/templates/services/NEO4J.md +0 -247
- package/templates/services/OPENTELEMETRY.md +0 -25
- package/templates/services/ORACLE.md +0 -290
- package/templates/services/PINO.md +0 -24
- package/templates/services/POSTGRESQL.md +0 -326
- package/templates/services/PROMETHEUS.md +0 -33
- package/templates/services/RABBITMQ.md +0 -286
- package/templates/services/REDIS.md +0 -292
- package/templates/services/S3.md +0 -298
- package/templates/services/SENTRY.md +0 -23
- package/templates/services/SQLITE.md +0 -294
- package/templates/services/SQLSERVER.md +0 -294
- package/templates/services/WINSTON.md +0 -30
- package/templates/skills/frameworks/angular/SKILL.md +0 -46
- package/templates/skills/frameworks/django/SKILL.md +0 -93
- package/templates/skills/frameworks/electron/SKILL.md +0 -157
- package/templates/skills/frameworks/flask/SKILL.md +0 -48
- package/templates/skills/frameworks/flutter/SKILL.md +0 -65
- package/templates/skills/frameworks/jquery/SKILL.md +0 -42
- package/templates/skills/frameworks/laravel/SKILL.md +0 -48
- package/templates/skills/frameworks/nestjs/SKILL.md +0 -53
- package/templates/skills/frameworks/nextjs/SKILL.md +0 -137
- package/templates/skills/frameworks/nuxt/SKILL.md +0 -50
- package/templates/skills/frameworks/rails/SKILL.md +0 -76
- package/templates/skills/frameworks/react/SKILL.md +0 -48
- package/templates/skills/frameworks/react-native/SKILL.md +0 -57
- package/templates/skills/frameworks/spring/SKILL.md +0 -49
- package/templates/skills/frameworks/symfony/SKILL.md +0 -46
- package/templates/skills/frameworks/vue/SKILL.md +0 -46
- package/templates/skills/frameworks/zend/SKILL.md +0 -45
- package/templates/skills/services/azure-blob/SKILL.md +0 -194
- package/templates/skills/services/cassandra/SKILL.md +0 -249
- package/templates/skills/services/dynamodb/SKILL.md +0 -318
- package/templates/skills/services/elasticsearch/SKILL.md +0 -357
- package/templates/skills/services/gcs/SKILL.md +0 -188
- package/templates/skills/services/influxdb/SKILL.md +0 -275
- package/templates/skills/services/kafka/SKILL.md +0 -351
- package/templates/skills/services/mariadb/SKILL.md +0 -193
- package/templates/skills/services/memcached/SKILL.md +0 -252
- package/templates/skills/services/minio/SKILL.md +0 -211
- package/templates/skills/services/mongodb/SKILL.md +0 -278
- package/templates/skills/services/mysql/SKILL.md +0 -368
- package/templates/skills/services/neo4j/SKILL.md +0 -257
- package/templates/skills/services/oracle/SKILL.md +0 -300
- package/templates/skills/services/postgresql/SKILL.md +0 -336
- package/templates/skills/services/rabbitmq/SKILL.md +0 -296
- package/templates/skills/services/redis/SKILL.md +0 -302
- package/templates/skills/services/s3/SKILL.md +0 -308
- package/templates/skills/services/sqlite/SKILL.md +0 -304
- package/templates/skills/services/sqlserver/SKILL.md +0 -304
- package/templates/skills/workflows/ralph/SETUP.md +0 -228
- package/templates/skills/workflows/ralph/SKILL.md +0 -309
- package/templates/skills/workflows/ralph/install.sh +0 -87
- package/templates/skills/workflows/ralph/manifest.json +0 -158
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { readFile, fileExists, writeFile, ensureDir } from '../../utils/file-system.js';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname } from 'path';
|
|
5
|
+
import { DecisionManager } from '../tasks/decision-manager.js';
|
|
6
|
+
import { KnowledgeManager } from '../tasks/knowledge-manager.js';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
// Resolve templates directory (handles both dev and production)
|
|
10
|
+
export function getTemplatesDir() {
|
|
11
|
+
// In production (dist/), templates are at package root
|
|
12
|
+
// In development (src/), templates are at package root
|
|
13
|
+
// Both resolve to same location
|
|
14
|
+
return path.join(__dirname, '..', '..', '..', 'templates');
|
|
15
|
+
}
|
|
16
|
+
// Helper to read core template files (AGENT_AUTOMATION, DOCUMENTATION_RULES, QUALITY_ENFORCEMENT, RULEBOOK)
|
|
17
|
+
async function generateCoreRules(name) {
|
|
18
|
+
const templatesDir = path.join(getTemplatesDir(), 'core');
|
|
19
|
+
const templatePath = path.join(templatesDir, `${name.toUpperCase()}.md`);
|
|
20
|
+
if (await fileExists(templatePath)) {
|
|
21
|
+
return await readFile(templatePath);
|
|
22
|
+
}
|
|
23
|
+
return `<!-- ${name.toUpperCase()}:START -->\n# ${name.charAt(0).toUpperCase() + name.slice(1)} Rules\n\nCore rules for ${name}.\n<!-- ${name.toUpperCase()}:END -->\n`;
|
|
24
|
+
}
|
|
25
|
+
export async function generateAgentsContent(config) {
|
|
26
|
+
const sections = [];
|
|
27
|
+
// Header comment
|
|
28
|
+
sections.push('<!-- RULEBOOK:START -->');
|
|
29
|
+
sections.push('# Project Rules');
|
|
30
|
+
sections.push('');
|
|
31
|
+
sections.push('Generated by @hivellm/rulebook');
|
|
32
|
+
sections.push(`Generated at: ${new Date().toISOString()}`);
|
|
33
|
+
sections.push('');
|
|
34
|
+
const rulebookDir = config.rulebookDir || '.rulebook';
|
|
35
|
+
// RULEBOOK.md has HIGHEST PRECEDENCE - must be first and most prominent
|
|
36
|
+
sections.push('## ⚠️ CRITICAL: Task Management Rules (HIGHEST PRECEDENCE)');
|
|
37
|
+
sections.push('');
|
|
38
|
+
sections.push('**MANDATORY**: All task creation MUST follow Rulebook task management system.');
|
|
39
|
+
sections.push('');
|
|
40
|
+
sections.push(`**📋 ALWAYS reference \`/${rulebookDir}/specs/RULEBOOK.md\` FIRST before creating any tasks.**`);
|
|
41
|
+
sections.push('');
|
|
42
|
+
sections.push('**Rules from RULEBOOK.md take precedence over all other rules in this file.**');
|
|
43
|
+
sections.push('');
|
|
44
|
+
sections.push('**Key Requirements:**');
|
|
45
|
+
sections.push('- ✅ Context7 MCP is REQUIRED for task creation');
|
|
46
|
+
sections.push('- ✅ All tasks MUST follow Rulebook task format');
|
|
47
|
+
sections.push('- ✅ Use `rulebook task create` to create tasks');
|
|
48
|
+
sections.push('- ✅ Always validate task format before committing');
|
|
49
|
+
sections.push('- ❌ NEVER create tasks without checking RULEBOOK.md format requirements');
|
|
50
|
+
sections.push('');
|
|
51
|
+
sections.push('### ⚠️ CRITICAL: Task File Structure Rules');
|
|
52
|
+
sections.push('');
|
|
53
|
+
sections.push('**MANDATORY**: When creating or updating tasks, you MUST follow the correct file structure:');
|
|
54
|
+
sections.push('');
|
|
55
|
+
sections.push('**✅ CORRECT File Structure:**');
|
|
56
|
+
sections.push('- `proposal.md` - **Why** and **What Changes** (detailed explanations go here)');
|
|
57
|
+
sections.push('- `tasks.md` - **ONLY checklist items** (simple `- [ ]` or `- [x]` format)');
|
|
58
|
+
sections.push('- `specs/<module>/spec.md` - **Technical specifications** (SHALL/MUST requirements)');
|
|
59
|
+
sections.push('- `design.md` - **Technical design decisions** (optional, for complex features)');
|
|
60
|
+
sections.push('');
|
|
61
|
+
sections.push('**❌ FORBIDDEN Practices:**');
|
|
62
|
+
sections.push('- ❌ **NEVER** add long explanations or specifications in `tasks.md`');
|
|
63
|
+
sections.push('- ❌ **NEVER** put technical details in `tasks.md` (use `specs/` instead)');
|
|
64
|
+
sections.push('- ❌ **NEVER** create `README.md` or `README` files in task directories');
|
|
65
|
+
sections.push('- ❌ **NEVER** create `PROCESS.md` or `PROCESS` files in task directories');
|
|
66
|
+
sections.push('- ❌ **NEVER** create any file not listed in the correct structure above');
|
|
67
|
+
sections.push('');
|
|
68
|
+
sections.push('**What Goes Where:**');
|
|
69
|
+
sections.push('');
|
|
70
|
+
sections.push('1. **`proposal.md`** - Use for:');
|
|
71
|
+
sections.push(' - Detailed "Why" explanations (minimum 20 characters)');
|
|
72
|
+
sections.push(' - "What Changes" descriptions');
|
|
73
|
+
sections.push(' - Impact analysis');
|
|
74
|
+
sections.push(' - Business/technical rationale');
|
|
75
|
+
sections.push('');
|
|
76
|
+
sections.push('2. **`tasks.md`** - Use ONLY for:');
|
|
77
|
+
sections.push(' - Simple checklist items: `- [ ] Task description`');
|
|
78
|
+
sections.push(' - Status updates: `- [x] Completed task`');
|
|
79
|
+
sections.push(' - Brief comments: `<!-- tested, coverage: 95% -->`');
|
|
80
|
+
sections.push(' - **DO NOT** add long explanations, specifications, or technical details here');
|
|
81
|
+
sections.push('');
|
|
82
|
+
sections.push('3. **`specs/<module>/spec.md`** - Use for:');
|
|
83
|
+
sections.push(' - Technical specifications with SHALL/MUST requirements');
|
|
84
|
+
sections.push(' - Scenario definitions (Given/When/Then)');
|
|
85
|
+
sections.push(' - Delta operations (ADDED/MODIFIED/REMOVED)');
|
|
86
|
+
sections.push(' - All detailed technical requirements');
|
|
87
|
+
sections.push('');
|
|
88
|
+
sections.push('4. **`design.md`** - Use for (optional):');
|
|
89
|
+
sections.push(' - Architecture decisions');
|
|
90
|
+
sections.push(' - Technical design rationale');
|
|
91
|
+
sections.push(' - Complex implementation details');
|
|
92
|
+
sections.push('');
|
|
93
|
+
sections.push('**Example of WRONG usage:**');
|
|
94
|
+
sections.push('```markdown');
|
|
95
|
+
sections.push('# tasks.md (WRONG - too much detail)');
|
|
96
|
+
sections.push('');
|
|
97
|
+
sections.push('## Implementation');
|
|
98
|
+
sections.push('- [ ] Create authentication system');
|
|
99
|
+
sections.push(' The system SHALL implement JWT-based authentication...');
|
|
100
|
+
sections.push(' Users MUST be able to login with email and password...');
|
|
101
|
+
sections.push(' The system MUST validate tokens...');
|
|
102
|
+
sections.push('```');
|
|
103
|
+
sections.push('');
|
|
104
|
+
sections.push('**Example of CORRECT usage:**');
|
|
105
|
+
sections.push('```markdown');
|
|
106
|
+
sections.push('# tasks.md (CORRECT - simple checklist)');
|
|
107
|
+
sections.push('');
|
|
108
|
+
sections.push('## 1. Implementation Phase');
|
|
109
|
+
sections.push('- [ ] 1.1 Create authentication module');
|
|
110
|
+
sections.push('- [ ] 1.2 Add JWT token generation');
|
|
111
|
+
sections.push('- [ ] 1.3 Implement password validation');
|
|
112
|
+
sections.push('');
|
|
113
|
+
sections.push('# specs/auth/spec.md (CORRECT - specifications here)');
|
|
114
|
+
sections.push('');
|
|
115
|
+
sections.push('## ADDED Requirements');
|
|
116
|
+
sections.push('');
|
|
117
|
+
sections.push('### Requirement: Authentication System');
|
|
118
|
+
sections.push('The system SHALL implement JWT-based authentication.');
|
|
119
|
+
sections.push('');
|
|
120
|
+
sections.push('#### Scenario: User Login');
|
|
121
|
+
sections.push('Given a user with valid credentials');
|
|
122
|
+
sections.push('When the user submits login form');
|
|
123
|
+
sections.push('Then the system MUST return a JWT token');
|
|
124
|
+
sections.push('```');
|
|
125
|
+
sections.push('');
|
|
126
|
+
sections.push('**Remember:**');
|
|
127
|
+
sections.push('- ✅ `tasks.md` = Simple checklist only');
|
|
128
|
+
sections.push('- ✅ `proposal.md` = Why and what changes');
|
|
129
|
+
sections.push('- ✅ `specs/` = Technical specifications');
|
|
130
|
+
sections.push('- ❌ No README, PROCESS, or other files');
|
|
131
|
+
sections.push('');
|
|
132
|
+
sections.push(`**For complete task management guidelines, see: \`/${rulebookDir}/specs/RULEBOOK.md\`**`);
|
|
133
|
+
sections.push('');
|
|
134
|
+
sections.push('---');
|
|
135
|
+
sections.push('');
|
|
136
|
+
// Core rules summary (detailed rules in /rulebook/)
|
|
137
|
+
sections.push('## Core Rules');
|
|
138
|
+
sections.push('');
|
|
139
|
+
sections.push('This project uses @hivellm/rulebook standards.');
|
|
140
|
+
sections.push('');
|
|
141
|
+
sections.push('**CRITICAL RULES:**');
|
|
142
|
+
sections.push('1. **ALWAYS check `RULEBOOK.md` first** when creating tasks');
|
|
143
|
+
sections.push(`2. Write tests first (${config.coverageThreshold}%+ coverage required)`);
|
|
144
|
+
sections.push('3. Run quality checks before committing:');
|
|
145
|
+
sections.push(' - Type check / Compiler check');
|
|
146
|
+
sections.push(' - Linter (no warnings allowed)');
|
|
147
|
+
sections.push(' - All tests (100% pass rate)');
|
|
148
|
+
sections.push(' - Coverage check');
|
|
149
|
+
sections.push('4. Update docs/ when implementing features');
|
|
150
|
+
sections.push('5. Follow strict documentation structure');
|
|
151
|
+
sections.push('6. **NEVER run destructive deletions (`rm -rf`) in this repository; when adding submodules always use `git submodule add`.**');
|
|
152
|
+
sections.push('7. **Temporary files and scripts**:');
|
|
153
|
+
sections.push(' - ✅ ALL scripts MUST be created in `/scripts` directory');
|
|
154
|
+
sections.push(' - ✅ ALL temporary files (test, log, debug) MUST be in `/scripts`');
|
|
155
|
+
sections.push(' - ✅ ALL temporary files MUST be removed immediately after use (MANDATORY)');
|
|
156
|
+
sections.push(' - ❌ NEVER create temporary files in project root or outside `/scripts`');
|
|
157
|
+
sections.push(' - ❌ NEVER leave temporary files after use - clean up before committing');
|
|
158
|
+
sections.push('');
|
|
159
|
+
sections.push('## Detailed Rules');
|
|
160
|
+
sections.push('');
|
|
161
|
+
sections.push(`For comprehensive rules, see the corresponding files in \`/${rulebookDir}/specs/\`:`);
|
|
162
|
+
sections.push('');
|
|
163
|
+
// TIER1_PROHIBITIONS is ALWAYS first (absolute highest precedence)
|
|
164
|
+
sections.push(`- \`/${rulebookDir}/specs/TIER1_PROHIBITIONS.md\` - **Absolute prohibitions (HIGHEST PRECEDENCE — read first)**`);
|
|
165
|
+
// RULEBOOK.md is second (task management)
|
|
166
|
+
sections.push(`- \`/${rulebookDir}/specs/RULEBOOK.md\` - **Task management rules**`);
|
|
167
|
+
// Only reference QUALITY_ENFORCEMENT if not in light mode
|
|
168
|
+
if (!config.lightMode) {
|
|
169
|
+
sections.push(`- \`/${rulebookDir}/specs/QUALITY_ENFORCEMENT.md\` - Quality enforcement rules`);
|
|
170
|
+
}
|
|
171
|
+
// Only reference GIT if enabled
|
|
172
|
+
if (config.includeGitWorkflow) {
|
|
173
|
+
sections.push(`- \`/${rulebookDir}/specs/GIT.md\` - Git workflow rules`);
|
|
174
|
+
}
|
|
175
|
+
// Token optimization reference
|
|
176
|
+
if (!config.lightMode) {
|
|
177
|
+
sections.push(`- \`/${rulebookDir}/specs/TOKEN_OPTIMIZATION.md\` - Model tier assignment and output verbosity rules`);
|
|
178
|
+
}
|
|
179
|
+
// Reference PLANS.md for session continuity
|
|
180
|
+
sections.push(`- \`/${rulebookDir}/PLANS.md\` - **Session scratchpad** (read at session start for current task context)`);
|
|
181
|
+
sections.push('');
|
|
182
|
+
sections.push(`Language-specific rules are in \`/${rulebookDir}/specs/\`.`);
|
|
183
|
+
sections.push(`Module-specific patterns are in \`/${rulebookDir}/specs/\`.`);
|
|
184
|
+
sections.push('');
|
|
185
|
+
sections.push('## Persistent Memory System');
|
|
186
|
+
sections.push('');
|
|
187
|
+
sections.push('This project uses a **persistent memory system** with hybrid BM25+vector search.');
|
|
188
|
+
sections.push('Memory is **enabled by default** and persists across sessions for maintaining context and preserving learnings.');
|
|
189
|
+
sections.push('');
|
|
190
|
+
sections.push('**MANDATORY: You MUST actively use memory to preserve context and learnings.**');
|
|
191
|
+
sections.push('');
|
|
192
|
+
sections.push('**Status**: ✅ Enabled by default in `.rulebook` configuration');
|
|
193
|
+
sections.push('');
|
|
194
|
+
sections.push('### Key Features');
|
|
195
|
+
sections.push('');
|
|
196
|
+
sections.push('- **Rich Contextual Summaries**: Memories auto-extract summaries with key concepts, decisions, patterns, gotchas');
|
|
197
|
+
sections.push('- **Hybrid Search**: BM25 keyword search + HNSW vector semantic search for relevant results');
|
|
198
|
+
sections.push('- **3-Layer Search Pattern**: Compact results → Timeline context → Full details (token-efficient)');
|
|
199
|
+
sections.push('- **Auto-Capture**: Implementation outputs from AI agents automatically captured');
|
|
200
|
+
sections.push('- **Zero Native Dependencies**: Pure WASM + TypeScript, works on all platforms');
|
|
201
|
+
sections.push('');
|
|
202
|
+
sections.push('### When to Save to Memory');
|
|
203
|
+
sections.push('');
|
|
204
|
+
sections.push('Save to memory whenever you:');
|
|
205
|
+
sections.push('- **Make an architectural decision** — why you chose one approach over another');
|
|
206
|
+
sections.push('- **Fix a bug** — root cause and how it was resolved');
|
|
207
|
+
sections.push('- **Discover something important** — codebase patterns, gotchas, constraints');
|
|
208
|
+
sections.push('- **Implement a feature** — design approach, patterns discovered, edge cases handled');
|
|
209
|
+
sections.push('- **Encounter an error** — root cause and solution for future reference');
|
|
210
|
+
sections.push('- **Receive user preferences** — coding style, conventions, workflow preferences');
|
|
211
|
+
sections.push('- **Complete a task or session** — summarize what was accomplished and learnings');
|
|
212
|
+
sections.push('');
|
|
213
|
+
sections.push('### How to Save Memory');
|
|
214
|
+
sections.push('');
|
|
215
|
+
sections.push('Save memories with rich context for better future searches:');
|
|
216
|
+
sections.push('');
|
|
217
|
+
sections.push('**Via MCP:**');
|
|
218
|
+
sections.push('```');
|
|
219
|
+
sections.push('rulebook_memory_save({');
|
|
220
|
+
sections.push(' type: "feature|decision|bugfix|discovery|refactor|change|observation",');
|
|
221
|
+
sections.push(' title: "Short title (≤80 chars)",');
|
|
222
|
+
sections.push(' content: "Detailed explanation: what was done, why, key decisions, patterns, gotchas...",');
|
|
223
|
+
sections.push(' tags: ["relevant", "tags"]');
|
|
224
|
+
sections.push('})');
|
|
225
|
+
sections.push('```');
|
|
226
|
+
sections.push('');
|
|
227
|
+
sections.push('**Via CLI:**');
|
|
228
|
+
sections.push('```bash');
|
|
229
|
+
sections.push('rulebook memory save "Detailed content here" --type feature --title "Brief Title" --tags tag1,tag2');
|
|
230
|
+
sections.push('```');
|
|
231
|
+
sections.push('');
|
|
232
|
+
sections.push('**Summary Auto-Extraction**: Summaries are automatically extracted from content, capturing:');
|
|
233
|
+
sections.push('- Key concepts and decisions');
|
|
234
|
+
sections.push('- Design patterns discovered');
|
|
235
|
+
sections.push('- Gotchas and edge cases');
|
|
236
|
+
sections.push('- Problem/solution context');
|
|
237
|
+
sections.push('');
|
|
238
|
+
sections.push('### When and How to Search Memory');
|
|
239
|
+
sections.push('');
|
|
240
|
+
sections.push('**At the START of every session**, search memory for relevant context:');
|
|
241
|
+
sections.push('');
|
|
242
|
+
sections.push('**Via MCP (3-Layer Search - token efficient):**');
|
|
243
|
+
sections.push('```');
|
|
244
|
+
sections.push('Layer 1 - Compact search: rulebook_memory_search({ query: "your topic", mode: "hybrid", limit: 10 })');
|
|
245
|
+
sections.push(' → Returns: id, title, type, score, summary (compact results)');
|
|
246
|
+
sections.push('Layer 2 - Timeline: rulebook_memory_timeline({ memoryId: "abc-123", window: 5 })');
|
|
247
|
+
sections.push(' → Returns: 5 before/after chronologically');
|
|
248
|
+
sections.push('Layer 3 - Full details: rulebook_memory_get({ ids: ["abc-123"] })');
|
|
249
|
+
sections.push(' → Returns: complete memory objects');
|
|
250
|
+
sections.push('```');
|
|
251
|
+
sections.push('');
|
|
252
|
+
sections.push('**Via CLI:**');
|
|
253
|
+
sections.push('```bash');
|
|
254
|
+
sections.push('rulebook memory search "authentication" --mode hybrid # Keyword + semantic');
|
|
255
|
+
sections.push('rulebook memory search "oauth" --type feature # Filter by memory type');
|
|
256
|
+
sections.push('rulebook memory list --limit 10 # Recent memories');
|
|
257
|
+
sections.push('```');
|
|
258
|
+
sections.push('');
|
|
259
|
+
sections.push('Also search when:');
|
|
260
|
+
sections.push("- Working on code you've touched before");
|
|
261
|
+
sections.push('- The user references a past discussion or decision');
|
|
262
|
+
sections.push('- You need context about why something was done a certain way');
|
|
263
|
+
sections.push('- **Before implementing similar features** — find past patterns and gotchas');
|
|
264
|
+
sections.push('');
|
|
265
|
+
sections.push('### Session Workflow');
|
|
266
|
+
sections.push('');
|
|
267
|
+
sections.push('**Complete memory-enhanced workflow:**');
|
|
268
|
+
sections.push('1. **Start of session**: Search memory for relevant past context');
|
|
269
|
+
sections.push('2. **During work**: Save discoveries, patterns, decisions as they happen');
|
|
270
|
+
sections.push('3. **After feature**: Save complete implementation with summaries');
|
|
271
|
+
sections.push('4. **End of session**: Save session summary for future sessions');
|
|
272
|
+
sections.push('');
|
|
273
|
+
sections.push('### Session Summary');
|
|
274
|
+
sections.push('');
|
|
275
|
+
sections.push('Before ending a session or when context is getting long, save a summary:');
|
|
276
|
+
sections.push('```');
|
|
277
|
+
sections.push('type: observation');
|
|
278
|
+
sections.push('title: "Session summary: <date or topic>"');
|
|
279
|
+
sections.push('content: "Accomplished: ... | Pending: ... | Key decisions: ..."');
|
|
280
|
+
sections.push('```');
|
|
281
|
+
sections.push('');
|
|
282
|
+
sections.push('When in doubt, ask to review @AGENTS.md first.');
|
|
283
|
+
sections.push('');
|
|
284
|
+
// Decision Records section — inject active ADRs if any exist
|
|
285
|
+
try {
|
|
286
|
+
const projectRoot = config.rulebookDir ? process.cwd() : process.cwd();
|
|
287
|
+
const dm = new DecisionManager(projectRoot, config.rulebookDir || '.rulebook');
|
|
288
|
+
const decisionContent = await dm.getForGenerator();
|
|
289
|
+
if (decisionContent) {
|
|
290
|
+
sections.push(decisionContent);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// No decisions directory yet — skip silently
|
|
295
|
+
}
|
|
296
|
+
// Project Knowledge section — inject patterns/anti-patterns if any exist
|
|
297
|
+
try {
|
|
298
|
+
const projectRoot = config.rulebookDir ? process.cwd() : process.cwd();
|
|
299
|
+
const km = new KnowledgeManager(projectRoot, config.rulebookDir || '.rulebook');
|
|
300
|
+
const knowledgeContent = await km.getForGenerator();
|
|
301
|
+
if (knowledgeContent) {
|
|
302
|
+
sections.push(knowledgeContent);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// No knowledge directory yet — skip silently
|
|
307
|
+
}
|
|
308
|
+
sections.push('<!-- RULEBOOK:END -->');
|
|
309
|
+
return sections.join('\n');
|
|
310
|
+
}
|
|
311
|
+
export async function generateLanguageRules(language) {
|
|
312
|
+
const templatesDir = path.join(getTemplatesDir(), 'languages');
|
|
313
|
+
const templatePath = path.join(templatesDir, `${language.toUpperCase()}.md`);
|
|
314
|
+
if (await fileExists(templatePath)) {
|
|
315
|
+
return await readFile(templatePath);
|
|
316
|
+
}
|
|
317
|
+
return `<!-- ${language.toUpperCase()}:START -->\n# ${language.charAt(0).toUpperCase() + language.slice(1)} Rules\n\nLanguage-specific rules for ${language}.\n<!-- ${language.toUpperCase()}:END -->\n`;
|
|
318
|
+
}
|
|
319
|
+
export async function generateModuleRules(module) {
|
|
320
|
+
const templatesDir = path.join(getTemplatesDir(), 'modules');
|
|
321
|
+
// Try UPPERCASE.md first, then kebab-case.md (e.g. sequential_thinking → sequential-thinking.md)
|
|
322
|
+
const candidates = [
|
|
323
|
+
path.join(templatesDir, `${module.toUpperCase()}.md`),
|
|
324
|
+
path.join(templatesDir, `${module.toLowerCase().replace(/_/g, '-')}.md`),
|
|
325
|
+
];
|
|
326
|
+
for (const templatePath of candidates) {
|
|
327
|
+
if (await fileExists(templatePath)) {
|
|
328
|
+
return await readFile(templatePath);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return `<!-- ${module.toUpperCase()}:START -->\n# ${module.charAt(0).toUpperCase() + module.slice(1)} Instructions\n\nModule-specific instructions for ${module}.\n<!-- ${module.toUpperCase()}:END -->\n`;
|
|
332
|
+
}
|
|
333
|
+
export async function generateGitRules(pushMode) {
|
|
334
|
+
const templatesDir = path.join(getTemplatesDir(), 'git');
|
|
335
|
+
const templatePath = path.join(templatesDir, 'GIT_WORKFLOW.md');
|
|
336
|
+
let gitRules = '';
|
|
337
|
+
if (await fileExists(templatePath)) {
|
|
338
|
+
gitRules = await readFile(templatePath);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
gitRules = `<!-- GIT:START -->\n# Git Workflow Rules\n\nGit workflow guidelines for this project.\n<!-- GIT:END -->\n`;
|
|
342
|
+
}
|
|
343
|
+
// Add push mode configuration
|
|
344
|
+
const pushModeConfig = `\n**AI Assistant Git Push Mode**: ${pushMode.toUpperCase()}\n\n`;
|
|
345
|
+
const pushModeInstructions = {
|
|
346
|
+
manual: `**CRITICAL**: Never execute \`git push\` commands automatically.
|
|
347
|
+
Always provide push commands for manual execution by the user.
|
|
348
|
+
|
|
349
|
+
Example:
|
|
350
|
+
\`\`\`
|
|
351
|
+
✋ MANUAL ACTION REQUIRED:
|
|
352
|
+
Run these commands manually (SSH password may be required):
|
|
353
|
+
git push origin main
|
|
354
|
+
git push origin v1.0.0
|
|
355
|
+
\`\`\``,
|
|
356
|
+
prompt: `**CRITICAL**: Always ask user permission before pushing.
|
|
357
|
+
|
|
358
|
+
Example:
|
|
359
|
+
\`\`\`
|
|
360
|
+
Ready to push changes. Execute these commands?
|
|
361
|
+
git push origin main
|
|
362
|
+
|
|
363
|
+
[Y/n]:
|
|
364
|
+
\`\`\``,
|
|
365
|
+
auto: `**INFO**: Automatic push enabled.
|
|
366
|
+
AI assistants may execute push commands automatically.
|
|
367
|
+
|
|
368
|
+
⚠️ Only use this mode if:
|
|
369
|
+
- SSH key has no password
|
|
370
|
+
- GitHub CLI is authenticated
|
|
371
|
+
- You trust the AI assistant completely`,
|
|
372
|
+
};
|
|
373
|
+
// Insert push mode config after <!-- GIT:START -->
|
|
374
|
+
gitRules = gitRules.replace('<!-- GIT:START -->', `<!-- GIT:START -->\n${pushModeConfig}${pushModeInstructions[pushMode]}\n`);
|
|
375
|
+
return gitRules;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Write modular directive file to /rulebook/ directory
|
|
379
|
+
* Adds header and footer comments for consistency
|
|
380
|
+
*/
|
|
381
|
+
async function writeModularFile(projectRoot, fileName, content, rulebookDir = '.rulebook') {
|
|
382
|
+
const specsPath = path.join(projectRoot, rulebookDir, 'specs');
|
|
383
|
+
await ensureDir(specsPath);
|
|
384
|
+
const filePath = path.join(specsPath, `${fileName}.md`);
|
|
385
|
+
// Add header comment if not already present
|
|
386
|
+
const headerComment = `<!-- ${fileName}:START -->\n`;
|
|
387
|
+
const footerComment = `\n<!-- ${fileName}:END -->`;
|
|
388
|
+
let finalContent = content.trim();
|
|
389
|
+
// Add header if not present
|
|
390
|
+
if (!finalContent.startsWith(headerComment.trim())) {
|
|
391
|
+
finalContent = headerComment + finalContent;
|
|
392
|
+
}
|
|
393
|
+
// Add footer if not present
|
|
394
|
+
if (!finalContent.endsWith(footerComment.trim())) {
|
|
395
|
+
finalContent = finalContent + footerComment;
|
|
396
|
+
}
|
|
397
|
+
await writeFile(filePath, finalContent);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Generate reference section for AGENTS.md
|
|
401
|
+
*/
|
|
402
|
+
function generateReferenceSection(name, fileName, description, quickRef, rulebookDir = '.rulebook') {
|
|
403
|
+
const sections = [];
|
|
404
|
+
sections.push(`### ${name}`);
|
|
405
|
+
sections.push('');
|
|
406
|
+
sections.push(`For comprehensive ${description}, see \`/${rulebookDir}/specs/${fileName}.md\``);
|
|
407
|
+
sections.push('');
|
|
408
|
+
sections.push('Quick reference:');
|
|
409
|
+
for (const item of quickRef) {
|
|
410
|
+
sections.push(`- ${item}`);
|
|
411
|
+
}
|
|
412
|
+
sections.push('');
|
|
413
|
+
return sections.join('\n');
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Generate language reference for AGENTS.md
|
|
417
|
+
*/
|
|
418
|
+
function generateLanguageReference(language, rulebookDir = '.rulebook') {
|
|
419
|
+
const languageName = language.charAt(0).toUpperCase() + language.slice(1);
|
|
420
|
+
const quickRef = [
|
|
421
|
+
'Type safety and strict mode',
|
|
422
|
+
'Code quality standards',
|
|
423
|
+
'Testing requirements (95%+ coverage)',
|
|
424
|
+
'Package management',
|
|
425
|
+
'Error handling patterns',
|
|
426
|
+
];
|
|
427
|
+
return generateReferenceSection(`${languageName} Development Rules`, language.toUpperCase(), `${languageName}-specific guidelines`, quickRef, rulebookDir);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Generate module reference for AGENTS.md
|
|
431
|
+
*/
|
|
432
|
+
function generateModuleReference(module, rulebookDir = '.rulebook') {
|
|
433
|
+
const moduleName = module.charAt(0).toUpperCase() + module.slice(1).replace(/_/g, ' ');
|
|
434
|
+
const quickRef = ['Module-specific instructions', 'Usage guidelines', 'Integration patterns'];
|
|
435
|
+
return generateReferenceSection(`${moduleName} Instructions`, module.toUpperCase(), `${moduleName}-specific instructions`, quickRef, rulebookDir);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Load project configuration from .rulebook file
|
|
439
|
+
*/
|
|
440
|
+
async function loadProjectConfigFromRulebook(projectRoot = process.cwd()) {
|
|
441
|
+
const { createConfigManager } = await import('../state/config-manager.js');
|
|
442
|
+
const configManager = createConfigManager(projectRoot);
|
|
443
|
+
try {
|
|
444
|
+
const rulebookConfig = await configManager.loadConfig();
|
|
445
|
+
// Map RulebookConfig to ProjectConfig
|
|
446
|
+
const projectConfig = {
|
|
447
|
+
languages: rulebookConfig.languages || [],
|
|
448
|
+
modules: rulebookConfig.modules || [],
|
|
449
|
+
modular: rulebookConfig.modular !== false, // Default to true
|
|
450
|
+
rulebookDir: rulebookConfig.rulebookDir || '.rulebook',
|
|
451
|
+
};
|
|
452
|
+
return projectConfig;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
// If .rulebook doesn't exist or can't be read, return empty config
|
|
456
|
+
return {};
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
const AGENT_REGISTRY = [
|
|
460
|
+
// Core agents
|
|
461
|
+
{
|
|
462
|
+
task: 'Implementation',
|
|
463
|
+
agent: 'implementer',
|
|
464
|
+
model: 'sonnet',
|
|
465
|
+
when: 'Writing new code or modifying existing',
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
task: 'Research',
|
|
469
|
+
agent: 'researcher',
|
|
470
|
+
model: 'haiku',
|
|
471
|
+
when: 'Exploring codebase, finding patterns',
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
task: 'Testing',
|
|
475
|
+
agent: 'tester',
|
|
476
|
+
model: 'sonnet',
|
|
477
|
+
when: 'Writing and running tests',
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
task: 'Documentation',
|
|
481
|
+
agent: 'docs-writer',
|
|
482
|
+
model: 'haiku',
|
|
483
|
+
when: 'README, docs, changelogs',
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
task: 'Code Review',
|
|
487
|
+
agent: 'code-reviewer',
|
|
488
|
+
model: 'sonnet',
|
|
489
|
+
when: 'Reviewing implementations for quality',
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
task: 'Build/CI',
|
|
493
|
+
agent: 'build-engineer',
|
|
494
|
+
model: 'sonnet',
|
|
495
|
+
when: 'Build failures, CI, dependencies',
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
task: 'Security',
|
|
499
|
+
agent: 'security-reviewer',
|
|
500
|
+
model: 'haiku',
|
|
501
|
+
when: 'Dependency audit, vulnerability review',
|
|
502
|
+
},
|
|
503
|
+
// Specialist agents
|
|
504
|
+
{
|
|
505
|
+
task: 'Architecture',
|
|
506
|
+
agent: 'architect',
|
|
507
|
+
model: 'opus',
|
|
508
|
+
when: 'System design, ADRs, scalability decisions',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
task: 'API Design',
|
|
512
|
+
agent: 'api-designer',
|
|
513
|
+
model: 'sonnet',
|
|
514
|
+
when: 'REST/GraphQL endpoints, OpenAPI specs',
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
task: 'Database',
|
|
518
|
+
agent: 'database-architect',
|
|
519
|
+
model: 'sonnet',
|
|
520
|
+
when: 'Schema design, migrations, query optimization',
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
task: 'DevOps',
|
|
524
|
+
agent: 'devops-engineer',
|
|
525
|
+
model: 'sonnet',
|
|
526
|
+
when: 'CI/CD, Docker, Kubernetes, infrastructure',
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
task: 'Performance',
|
|
530
|
+
agent: 'performance-engineer',
|
|
531
|
+
model: 'sonnet',
|
|
532
|
+
when: 'Profiling, benchmarks, optimization',
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
task: 'Refactoring',
|
|
536
|
+
agent: 'refactoring-agent',
|
|
537
|
+
model: 'sonnet',
|
|
538
|
+
when: 'Code smells, complexity reduction, cleanup',
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
task: 'Migration',
|
|
542
|
+
agent: 'migration-engineer',
|
|
543
|
+
model: 'sonnet',
|
|
544
|
+
when: 'DB migrations, API migrations, upgrades',
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
task: 'Accessibility',
|
|
548
|
+
agent: 'accessibility-reviewer',
|
|
549
|
+
model: 'haiku',
|
|
550
|
+
when: 'WCAG compliance, ARIA, screen readers',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
task: 'i18n',
|
|
554
|
+
agent: 'i18n-engineer',
|
|
555
|
+
model: 'haiku',
|
|
556
|
+
when: 'Internationalization, localization, RTL',
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
task: 'UX Review',
|
|
560
|
+
agent: 'ux-reviewer',
|
|
561
|
+
model: 'haiku',
|
|
562
|
+
when: 'Usability, interaction patterns, error states',
|
|
563
|
+
},
|
|
564
|
+
// Orchestration
|
|
565
|
+
{
|
|
566
|
+
task: 'Orchestration',
|
|
567
|
+
agent: 'team-lead',
|
|
568
|
+
model: 'opus',
|
|
569
|
+
when: 'Multi-agent coordination for complex tasks',
|
|
570
|
+
},
|
|
571
|
+
];
|
|
572
|
+
/**
|
|
573
|
+
* Generate the agent delegation section for AGENTS.md.
|
|
574
|
+
* Adapts table based on detected languages.
|
|
575
|
+
*/
|
|
576
|
+
export function generateDelegationSection(config) {
|
|
577
|
+
const lines = [];
|
|
578
|
+
const primaryLang = config.languages?.[0] || 'the project language';
|
|
579
|
+
lines.push('## Agent Delegation');
|
|
580
|
+
lines.push('');
|
|
581
|
+
lines.push('Delegate work to specialist agents instead of doing everything in the main conversation. Each agent uses a cost-appropriate model.');
|
|
582
|
+
lines.push('');
|
|
583
|
+
lines.push('| Task | Agent | Model | When to use |');
|
|
584
|
+
lines.push('|------|-------|-------|-------------|');
|
|
585
|
+
for (const entry of AGENT_REGISTRY) {
|
|
586
|
+
lines.push(`| ${entry.task} | ${entry.agent} | ${entry.model} | ${entry.when} |`);
|
|
587
|
+
}
|
|
588
|
+
lines.push('');
|
|
589
|
+
lines.push('### Delegation Rules');
|
|
590
|
+
lines.push('');
|
|
591
|
+
lines.push('1. **Never write code directly in the main conversation** — delegate to the appropriate agent');
|
|
592
|
+
lines.push('2. **After implementing code**, launch tester + docs-writer in parallel to update tests and documentation');
|
|
593
|
+
lines.push('3. **The main conversation** serves for planning, coordination, and user communication only');
|
|
594
|
+
lines.push('4. **Use haiku agents** (researcher, docs-writer, security-reviewer) for read-only tasks — they are significantly cheaper');
|
|
595
|
+
lines.push('5. **Launch independent agents in parallel** when possible to maximize throughput');
|
|
596
|
+
lines.push('');
|
|
597
|
+
lines.push(`> **Project context**: Primary language is **${primaryLang}**. Agents are pre-configured with this context.`);
|
|
598
|
+
lines.push('');
|
|
599
|
+
return lines.join('\n');
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Resolve placeholder values from project config.
|
|
603
|
+
*/
|
|
604
|
+
export function resolveAgentPlaceholders(config) {
|
|
605
|
+
const primaryLang = config.languages?.[0] || 'TypeScript';
|
|
606
|
+
// Map language to common test framework
|
|
607
|
+
const testFrameworkMap = {
|
|
608
|
+
typescript: 'vitest',
|
|
609
|
+
javascript: 'jest',
|
|
610
|
+
python: 'pytest',
|
|
611
|
+
rust: 'cargo test',
|
|
612
|
+
go: 'go test',
|
|
613
|
+
java: 'JUnit',
|
|
614
|
+
csharp: 'xUnit',
|
|
615
|
+
ruby: 'RSpec',
|
|
616
|
+
php: 'PHPUnit',
|
|
617
|
+
swift: 'XCTest',
|
|
618
|
+
kotlin: 'JUnit',
|
|
619
|
+
dart: 'flutter test',
|
|
620
|
+
elixir: 'ExUnit',
|
|
621
|
+
scala: 'ScalaTest',
|
|
622
|
+
};
|
|
623
|
+
// Map language to file naming convention
|
|
624
|
+
const fileNamingMap = {
|
|
625
|
+
typescript: 'kebab-case',
|
|
626
|
+
javascript: 'kebab-case',
|
|
627
|
+
python: 'snake_case',
|
|
628
|
+
rust: 'snake_case',
|
|
629
|
+
go: 'snake_case',
|
|
630
|
+
java: 'PascalCase',
|
|
631
|
+
csharp: 'PascalCase',
|
|
632
|
+
ruby: 'snake_case',
|
|
633
|
+
php: 'PascalCase',
|
|
634
|
+
swift: 'PascalCase',
|
|
635
|
+
kotlin: 'PascalCase',
|
|
636
|
+
dart: 'snake_case',
|
|
637
|
+
elixir: 'snake_case',
|
|
638
|
+
scala: 'PascalCase',
|
|
639
|
+
};
|
|
640
|
+
const langKey = primaryLang.toLowerCase();
|
|
641
|
+
return {
|
|
642
|
+
'{{language}}': primaryLang,
|
|
643
|
+
'{{framework}}': 'none',
|
|
644
|
+
'{{test_framework}}': testFrameworkMap[langKey] || 'the project test framework',
|
|
645
|
+
'{{file_naming}}': fileNamingMap[langKey] || 'kebab-case',
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Substitute placeholders in agent template content.
|
|
650
|
+
*/
|
|
651
|
+
export function substituteAgentPlaceholders(content, placeholders) {
|
|
652
|
+
let result = content;
|
|
653
|
+
for (const [key, value] of Object.entries(placeholders)) {
|
|
654
|
+
result = result.replaceAll(key, value);
|
|
655
|
+
}
|
|
656
|
+
return result;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Install agent definitions to .claude/agents/ with placeholder substitution.
|
|
660
|
+
*/
|
|
661
|
+
async function installAgentsWithPlaceholders(projectRoot, config) {
|
|
662
|
+
const agentsDir = path.join(getTemplatesDir(), 'agents');
|
|
663
|
+
const targetDir = path.join(projectRoot, '.claude', 'agents');
|
|
664
|
+
if (!(await fileExists(agentsDir)))
|
|
665
|
+
return;
|
|
666
|
+
await ensureDir(targetDir);
|
|
667
|
+
const placeholders = resolveAgentPlaceholders(config);
|
|
668
|
+
const { readdirSync } = await import('fs');
|
|
669
|
+
const files = readdirSync(agentsDir).filter((f) => f.endsWith('.md'));
|
|
670
|
+
for (const file of files) {
|
|
671
|
+
const content = await readFile(path.join(agentsDir, file));
|
|
672
|
+
const substituted = substituteAgentPlaceholders(content, placeholders);
|
|
673
|
+
await writeFile(path.join(targetDir, file), substituted);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Names of `core/` skills that are user-invocable (slash-command or
|
|
678
|
+
* natural-language trigger), so their SKILL.md files must land in
|
|
679
|
+
* `.claude/skills/` alongside the `dev/` skills. Non-invocable core
|
|
680
|
+
* skills (agent-automation, dag, documentation-rules, quality-enforcement,
|
|
681
|
+
* rulebook) stay referenced via AGENTS.md only.
|
|
682
|
+
*/
|
|
683
|
+
export const INVOCABLE_CORE_SKILLS = [
|
|
684
|
+
'rulebook-terse',
|
|
685
|
+
'rulebook-terse-commit',
|
|
686
|
+
'rulebook-terse-review',
|
|
687
|
+
'karpathy-guidelines',
|
|
688
|
+
];
|
|
689
|
+
/**
|
|
690
|
+
* Copy every SKILL.md under a source directory into .claude/skills/.
|
|
691
|
+
* Used for both the full `dev/` category and a curated subset of `core/`
|
|
692
|
+
* skills (see INVOCABLE_CORE_SKILLS).
|
|
693
|
+
*
|
|
694
|
+
* Exported for test coverage of the install pipeline.
|
|
695
|
+
*/
|
|
696
|
+
export async function installSkillsFromSource(sourceDir, targetSkillsDir, filter) {
|
|
697
|
+
const { readdirSync, statSync } = await import('fs');
|
|
698
|
+
if (!(await fileExists(sourceDir)))
|
|
699
|
+
return;
|
|
700
|
+
await ensureDir(targetSkillsDir);
|
|
701
|
+
const entries = readdirSync(sourceDir);
|
|
702
|
+
for (const entry of entries) {
|
|
703
|
+
if (filter && !filter.includes(entry))
|
|
704
|
+
continue;
|
|
705
|
+
const entryPath = path.join(sourceDir, entry);
|
|
706
|
+
if (!statSync(entryPath).isDirectory())
|
|
707
|
+
continue;
|
|
708
|
+
const skillFile = path.join(entryPath, 'SKILL.md');
|
|
709
|
+
if (!(await fileExists(skillFile)))
|
|
710
|
+
continue;
|
|
711
|
+
const targetSkillDir = path.join(targetSkillsDir, entry);
|
|
712
|
+
await ensureDir(targetSkillDir);
|
|
713
|
+
const content = await readFile(skillFile);
|
|
714
|
+
await writeFile(path.join(targetSkillDir, 'SKILL.md'), content);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Install dev skills + invocable core skills to .claude/skills/ (modern
|
|
719
|
+
* Claude Code skills format). Each skill is a directory with a SKILL.md
|
|
720
|
+
* file. Always installed on init/update — useful for any project.
|
|
721
|
+
*/
|
|
722
|
+
async function installDevSkillsFromTemplates(projectRoot) {
|
|
723
|
+
const skillsTargetDir = path.join(projectRoot, '.claude', 'skills');
|
|
724
|
+
const templatesRoot = getTemplatesDir();
|
|
725
|
+
await installSkillsFromSource(path.join(templatesRoot, 'skills', 'dev'), skillsTargetDir);
|
|
726
|
+
await installSkillsFromSource(path.join(templatesRoot, 'skills', 'core'), skillsTargetDir, INVOCABLE_CORE_SKILLS);
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Generate modular AGENTS.md with references
|
|
730
|
+
*/
|
|
731
|
+
export async function generateModularAgents(config, projectRoot = process.cwd()) {
|
|
732
|
+
// Load saved configuration from .rulebook and merge with provided config
|
|
733
|
+
const savedConfig = await loadProjectConfigFromRulebook(projectRoot);
|
|
734
|
+
// Merge: saved config takes precedence for languages/modules
|
|
735
|
+
// provided config takes precedence for other settings (like rulebookDir when explicitly set)
|
|
736
|
+
const mergedConfig = {
|
|
737
|
+
...config,
|
|
738
|
+
languages: savedConfig.languages?.length ? savedConfig.languages : config.languages,
|
|
739
|
+
modules: savedConfig.modules?.length ? savedConfig.modules : config.modules,
|
|
740
|
+
modular: savedConfig.modular !== undefined ? savedConfig.modular : config.modular !== false,
|
|
741
|
+
// rulebookDir: provided config takes precedence if explicitly set, otherwise use saved or default
|
|
742
|
+
rulebookDir: config.rulebookDir || savedConfig.rulebookDir || '.rulebook',
|
|
743
|
+
};
|
|
744
|
+
const rulebookDir = mergedConfig.rulebookDir || '.rulebook';
|
|
745
|
+
const sections = [];
|
|
746
|
+
// Add Rulebook section (core rules stay embedded - simplified)
|
|
747
|
+
sections.push(await generateAgentsContent(mergedConfig));
|
|
748
|
+
sections.push('');
|
|
749
|
+
// Write RULEBOOK.md to /rulebook/ (ALWAYS included - highest precedence)
|
|
750
|
+
const rulebookContent = await generateCoreRules('RULEBOOK');
|
|
751
|
+
await writeModularFile(projectRoot, 'RULEBOOK', rulebookContent.trim(), rulebookDir);
|
|
752
|
+
// Write QUALITY_ENFORCEMENT to /rulebook/ (always included unless light mode)
|
|
753
|
+
if (!mergedConfig.lightMode) {
|
|
754
|
+
const enforcementContent = await generateCoreRules('QUALITY_ENFORCEMENT');
|
|
755
|
+
await writeModularFile(projectRoot, 'QUALITY_ENFORCEMENT', enforcementContent.trim(), rulebookDir);
|
|
756
|
+
}
|
|
757
|
+
// Write TIER1_PROHIBITIONS to /rulebook/ (always included — highest precedence directives)
|
|
758
|
+
const tier1Content = await generateCoreRules('TIER1_PROHIBITIONS');
|
|
759
|
+
if (tier1Content.trim()) {
|
|
760
|
+
await writeModularFile(projectRoot, 'TIER1_PROHIBITIONS', tier1Content.trim(), rulebookDir);
|
|
761
|
+
}
|
|
762
|
+
// Write TOKEN_OPTIMIZATION to /rulebook/ (always included unless light mode)
|
|
763
|
+
if (!mergedConfig.lightMode) {
|
|
764
|
+
const tokenOptContent = await generateCoreRules('TOKEN_OPTIMIZATION');
|
|
765
|
+
if (tokenOptContent.trim()) {
|
|
766
|
+
await writeModularFile(projectRoot, 'TOKEN_OPTIMIZATION', tokenOptContent.trim(), rulebookDir);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
// Write Git workflow rules to /.rulebook/specs/GIT.md
|
|
770
|
+
if (mergedConfig.includeGitWorkflow) {
|
|
771
|
+
const gitRules = await generateGitRules(mergedConfig.gitPushMode || 'manual');
|
|
772
|
+
await writeModularFile(projectRoot, 'GIT', gitRules.trim(), rulebookDir);
|
|
773
|
+
}
|
|
774
|
+
// If WORKSPACE.md spec exists, add reference in AGENTS.md
|
|
775
|
+
{
|
|
776
|
+
const { existsSync } = await import('fs');
|
|
777
|
+
const wsSpecPath = path.join(projectRoot, rulebookDir, 'specs', 'WORKSPACE.md');
|
|
778
|
+
if (existsSync(wsSpecPath)) {
|
|
779
|
+
sections.push('## Workspace Mode');
|
|
780
|
+
sections.push('');
|
|
781
|
+
sections.push(`**This project is part of a multi-project workspace.** All MCP tool calls MUST include the correct \`projectId\` parameter.`);
|
|
782
|
+
sections.push('');
|
|
783
|
+
sections.push(`**📋 ALWAYS read \`/${rulebookDir}/specs/WORKSPACE.md\` to understand project routing before using any Rulebook MCP tools.**`);
|
|
784
|
+
sections.push('');
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
// Write language files and add references
|
|
788
|
+
if (mergedConfig.languages.length > 0) {
|
|
789
|
+
sections.push('## Language-Specific Rules');
|
|
790
|
+
sections.push('');
|
|
791
|
+
sections.push(`The following languages are configured for this project. For detailed rules, see the corresponding files in \`/${rulebookDir}/specs/\`:`);
|
|
792
|
+
sections.push('');
|
|
793
|
+
// Write all language files first
|
|
794
|
+
for (const language of mergedConfig.languages) {
|
|
795
|
+
const langRules = await generateLanguageRules(language);
|
|
796
|
+
await writeModularFile(projectRoot, language.toUpperCase(), langRules, rulebookDir);
|
|
797
|
+
}
|
|
798
|
+
// Then add all references together
|
|
799
|
+
for (const language of mergedConfig.languages) {
|
|
800
|
+
sections.push(generateLanguageReference(language, rulebookDir));
|
|
801
|
+
}
|
|
802
|
+
sections.push(`**Usage**: When working with language-specific code, reference the corresponding \`/${rulebookDir}/specs/[LANGUAGE].md\` file for detailed guidelines.`);
|
|
803
|
+
sections.push('');
|
|
804
|
+
}
|
|
805
|
+
// Write module files and add references
|
|
806
|
+
// First, write AGENT_AUTOMATION if not minimal (core file, not module)
|
|
807
|
+
if (!mergedConfig.minimal) {
|
|
808
|
+
const agentAutomation = await generateCoreRules('AGENT_AUTOMATION');
|
|
809
|
+
await writeModularFile(projectRoot, 'AGENT_AUTOMATION', agentAutomation, rulebookDir);
|
|
810
|
+
}
|
|
811
|
+
// Write MULTI_AGENT directives (after AGENT_AUTOMATION)
|
|
812
|
+
if (!mergedConfig.minimal) {
|
|
813
|
+
const multiAgentContent = await generateCoreRules('MULTI_AGENT');
|
|
814
|
+
await writeModularFile(projectRoot, 'MULTI_AGENT', multiAgentContent, rulebookDir);
|
|
815
|
+
}
|
|
816
|
+
// Then handle all modules together
|
|
817
|
+
const allModules = [];
|
|
818
|
+
if (!mergedConfig.minimal) {
|
|
819
|
+
allModules.push('agent_automation');
|
|
820
|
+
allModules.push('multi_agent');
|
|
821
|
+
}
|
|
822
|
+
allModules.push(...mergedConfig.modules);
|
|
823
|
+
if (allModules.length > 0) {
|
|
824
|
+
sections.push('## Module-Specific Instructions');
|
|
825
|
+
sections.push('');
|
|
826
|
+
sections.push(`The following modules are configured for this project. For detailed instructions, see the corresponding files in \`/${rulebookDir}/specs/\`:`);
|
|
827
|
+
sections.push('');
|
|
828
|
+
// Write all module files first (except AGENT_AUTOMATION which is already written)
|
|
829
|
+
for (const module of mergedConfig.modules) {
|
|
830
|
+
const moduleRules = await generateModuleRules(module);
|
|
831
|
+
await writeModularFile(projectRoot, module.toUpperCase(), moduleRules, rulebookDir);
|
|
832
|
+
}
|
|
833
|
+
// Then add all references together
|
|
834
|
+
if (!mergedConfig.minimal) {
|
|
835
|
+
sections.push(generateModuleReference('agent_automation', rulebookDir));
|
|
836
|
+
sections.push(generateModuleReference('multi_agent', rulebookDir));
|
|
837
|
+
}
|
|
838
|
+
for (const module of mergedConfig.modules) {
|
|
839
|
+
sections.push(generateModuleReference(module, rulebookDir));
|
|
840
|
+
}
|
|
841
|
+
sections.push(`**Usage**: When working with module-specific features, reference the corresponding \`/${rulebookDir}/specs/[MODULE].md\` file for detailed instructions.`);
|
|
842
|
+
sections.push('');
|
|
843
|
+
}
|
|
844
|
+
// Add enabled skills section (v2.0)
|
|
845
|
+
try {
|
|
846
|
+
const { SkillsManager, getDefaultTemplatesPath } = await import('../skills/skills-manager.js');
|
|
847
|
+
const { createConfigManager } = await import('../state/config-manager.js');
|
|
848
|
+
const configManager = createConfigManager(projectRoot);
|
|
849
|
+
const rulebookConfig = await configManager.loadConfig();
|
|
850
|
+
if (rulebookConfig.skills?.enabled && rulebookConfig.skills.enabled.length > 0) {
|
|
851
|
+
const skillsManager = new SkillsManager(getDefaultTemplatesPath(), projectRoot);
|
|
852
|
+
const enabledSkills = await skillsManager.getEnabledSkills(rulebookConfig);
|
|
853
|
+
// Add capabilities summary
|
|
854
|
+
if (enabledSkills.length > 0) {
|
|
855
|
+
sections.push('## Project Capabilities');
|
|
856
|
+
sections.push('');
|
|
857
|
+
sections.push('This project has the following AI-assisted capabilities enabled:');
|
|
858
|
+
sections.push('');
|
|
859
|
+
// Group skills by category for summary
|
|
860
|
+
const categorySummary = new Map();
|
|
861
|
+
for (const skill of enabledSkills) {
|
|
862
|
+
const category = skill.category;
|
|
863
|
+
if (!categorySummary.has(category)) {
|
|
864
|
+
categorySummary.set(category, []);
|
|
865
|
+
}
|
|
866
|
+
categorySummary.get(category)?.push(skill.metadata.name);
|
|
867
|
+
}
|
|
868
|
+
for (const [category, skills] of categorySummary.entries()) {
|
|
869
|
+
const categoryLabel = category.charAt(0).toUpperCase() + category.slice(1);
|
|
870
|
+
sections.push(`- **${categoryLabel}**: ${skills.join(', ')}`);
|
|
871
|
+
}
|
|
872
|
+
sections.push('');
|
|
873
|
+
sections.push('Use `rulebook skill list` to see all available skills.');
|
|
874
|
+
sections.push('Use `rulebook skill add <skill-id>` to enable additional skills.');
|
|
875
|
+
sections.push('');
|
|
876
|
+
}
|
|
877
|
+
// Add skills content (includes index and detailed rules)
|
|
878
|
+
const skillsContent = await skillsManager.mergeSkillsContent(rulebookConfig);
|
|
879
|
+
if (skillsContent) {
|
|
880
|
+
sections.push(skillsContent);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
catch {
|
|
885
|
+
// Skills not configured or error loading - skip silently
|
|
886
|
+
}
|
|
887
|
+
// Add monorepo package index and generate per-package AGENTS.md if monorepo detected
|
|
888
|
+
try {
|
|
889
|
+
const { detectMonorepo } = await import('../detect/detector.js');
|
|
890
|
+
const monorepo = await detectMonorepo(projectRoot);
|
|
891
|
+
if (monorepo.detected && monorepo.packages.length > 0) {
|
|
892
|
+
sections.push('## Monorepo Package Index');
|
|
893
|
+
sections.push('');
|
|
894
|
+
sections.push(`Monorepo tool: **${monorepo.tool}**`);
|
|
895
|
+
sections.push('');
|
|
896
|
+
sections.push('Packages:');
|
|
897
|
+
for (const pkg of monorepo.packages) {
|
|
898
|
+
sections.push(`- \`${pkg}/\` — see \`${pkg}/AGENTS.md\` for package-specific rules`);
|
|
899
|
+
}
|
|
900
|
+
sections.push('');
|
|
901
|
+
// Generate per-package AGENTS.md files
|
|
902
|
+
for (const pkg of monorepo.packages) {
|
|
903
|
+
await generatePackageAgentsMd(path.join(projectRoot, pkg), mergedConfig, projectRoot).catch(() => {
|
|
904
|
+
/* skip on error */
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
catch {
|
|
910
|
+
// Monorepo detection failed — skip silently
|
|
911
|
+
}
|
|
912
|
+
// Generate multi-tool IDE config files (GEMINI.md, .windsurfrules, etc.)
|
|
913
|
+
try {
|
|
914
|
+
const { detectGeminiCli, detectContinueDev, detectWindsurf, detectGithubCopilot } = await import('../detect/detector.js');
|
|
915
|
+
const { generateMultiToolConfigs } = await import('../ide/multi-tool-generator.js');
|
|
916
|
+
const [geminiCli, continueDev, windsurf, githubCopilot] = await Promise.all([
|
|
917
|
+
detectGeminiCli(projectRoot),
|
|
918
|
+
detectContinueDev(projectRoot),
|
|
919
|
+
detectWindsurf(projectRoot),
|
|
920
|
+
detectGithubCopilot(projectRoot),
|
|
921
|
+
]);
|
|
922
|
+
await generateMultiToolConfigs(projectRoot, {
|
|
923
|
+
languages: [],
|
|
924
|
+
modules: [],
|
|
925
|
+
existingAgents: null,
|
|
926
|
+
geminiCli,
|
|
927
|
+
continueDev,
|
|
928
|
+
windsurf,
|
|
929
|
+
githubCopilot,
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
catch {
|
|
933
|
+
// Multi-tool generation failed - skip silently
|
|
934
|
+
}
|
|
935
|
+
// Generate agent delegation section
|
|
936
|
+
sections.push(generateDelegationSection(mergedConfig));
|
|
937
|
+
// Install agent definitions and dev skills to .claude/
|
|
938
|
+
try {
|
|
939
|
+
await installAgentsWithPlaceholders(projectRoot, mergedConfig);
|
|
940
|
+
await installDevSkillsFromTemplates(projectRoot);
|
|
941
|
+
}
|
|
942
|
+
catch {
|
|
943
|
+
// Agent/skill installation failed — skip silently
|
|
944
|
+
}
|
|
945
|
+
// Append AGENTS.override.md content if present and non-empty
|
|
946
|
+
try {
|
|
947
|
+
const { readOverrideContent } = await import('../state/override-manager.js');
|
|
948
|
+
const overrideContent = await readOverrideContent(projectRoot);
|
|
949
|
+
if (overrideContent) {
|
|
950
|
+
sections.push('');
|
|
951
|
+
sections.push('## Project-Specific Overrides');
|
|
952
|
+
sections.push('');
|
|
953
|
+
sections.push(overrideContent);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
catch {
|
|
957
|
+
// Override reading failed — skip silently
|
|
958
|
+
}
|
|
959
|
+
return sections.join('\n').trim() + '\n';
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Generate a minimal AGENTS.md for an individual package inside a monorepo.
|
|
963
|
+
* Inherits language detection from the package root and links back to the root AGENTS.md.
|
|
964
|
+
*/
|
|
965
|
+
export async function generatePackageAgentsMd(packageRoot, rootConfig, monorepoRoot) {
|
|
966
|
+
const { existsSync } = await import('fs');
|
|
967
|
+
const { detectProject } = await import('../detect/detector.js');
|
|
968
|
+
const agentsPath = path.join(packageRoot, 'AGENTS.md');
|
|
969
|
+
// Don't overwrite if already customized (has RULEBOOK markers)
|
|
970
|
+
if (existsSync(agentsPath)) {
|
|
971
|
+
const existing = await readFile(agentsPath).catch(() => '');
|
|
972
|
+
if (existing.includes('<!-- RULEBOOK:START -->'))
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
// Detect languages specific to this package
|
|
976
|
+
const pkgDetection = await detectProject(packageRoot).catch(() => null);
|
|
977
|
+
const langList = pkgDetection
|
|
978
|
+
? pkgDetection.languages.map((l) => l.language)
|
|
979
|
+
: rootConfig.languages;
|
|
980
|
+
const relRoot = path.relative(packageRoot, monorepoRoot) || '..';
|
|
981
|
+
const content = [
|
|
982
|
+
'<!-- RULEBOOK:START -->',
|
|
983
|
+
`# Package Agent Directives`,
|
|
984
|
+
'',
|
|
985
|
+
`> Part of a monorepo. Root rules: [\`${relRoot}/AGENTS.md\`](${relRoot}/AGENTS.md)`,
|
|
986
|
+
'',
|
|
987
|
+
'## Languages',
|
|
988
|
+
'',
|
|
989
|
+
langList.length > 0
|
|
990
|
+
? langList.map((l) => `- ${l.toUpperCase()}`).join('\n')
|
|
991
|
+
: '- (inherits from root)',
|
|
992
|
+
'',
|
|
993
|
+
'## Rules',
|
|
994
|
+
'',
|
|
995
|
+
`- Follow root AGENTS.md for task management and quality gates`,
|
|
996
|
+
`- Package-specific overrides go in \`AGENTS.override.md\` (if present)`,
|
|
997
|
+
'<!-- RULEBOOK:END -->',
|
|
998
|
+
'',
|
|
999
|
+
].join('\n');
|
|
1000
|
+
await writeFile(agentsPath, content);
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Generate lean AGENTS.md — a lightweight index (< 3KB) referencing spec files.
|
|
1004
|
+
* All spec files are still written to .rulebook/specs/ by generateModularAgents.
|
|
1005
|
+
*/
|
|
1006
|
+
export async function generateLeanAgents(config, projectRoot = process.cwd()) {
|
|
1007
|
+
// First run modular generation to ensure all spec files are up to date
|
|
1008
|
+
await generateModularAgents(config, projectRoot);
|
|
1009
|
+
const rulebookDir = config.rulebookDir || '.rulebook';
|
|
1010
|
+
// Load lean template
|
|
1011
|
+
const templatesDir = path.join(getTemplatesDir(), 'core');
|
|
1012
|
+
const leanTemplatePath = path.join(templatesDir, 'AGENTS_LEAN.md');
|
|
1013
|
+
let template = '';
|
|
1014
|
+
if (await fileExists(leanTemplatePath)) {
|
|
1015
|
+
template = await readFile(leanTemplatePath);
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
template = `<!-- RULEBOOK:START -->\n# Project Agent Directives\n\nSee \`/${rulebookDir}/specs/\` for all rules.\n\n- **Task Management**: \`/${rulebookDir}/specs/RULEBOOK.md\`\n- **Quality Gates**: \`/${rulebookDir}/specs/QUALITY_ENFORCEMENT.md\`\n- **Git Workflow**: \`/${rulebookDir}/specs/GIT.md\`\n<!-- RULEBOOK:END -->\n`;
|
|
1019
|
+
}
|
|
1020
|
+
// Build language refs
|
|
1021
|
+
const langRefs = config.languages
|
|
1022
|
+
.map((lang) => `- **${lang.toUpperCase()}**: \`/${rulebookDir}/specs/${lang.toUpperCase()}.md\``)
|
|
1023
|
+
.join('\n');
|
|
1024
|
+
template = template.replace('LANGUAGE_REFS', langRefs || '_None configured_');
|
|
1025
|
+
// Build module refs (core + user modules)
|
|
1026
|
+
const coreModules = config.minimal ? [] : ['agent_automation', 'multi_agent'];
|
|
1027
|
+
const allModules = [...coreModules, ...(config.modules || [])];
|
|
1028
|
+
const moduleRefs = allModules
|
|
1029
|
+
.map((mod) => `- **${mod.toUpperCase()}**: \`/${rulebookDir}/specs/${mod.toUpperCase()}.md\``)
|
|
1030
|
+
.join('\n');
|
|
1031
|
+
template = template.replace('MODULE_REFS', moduleRefs || '_None configured_');
|
|
1032
|
+
return template;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Generate full AGENTS.md (modular by default, legacy mode available)
|
|
1036
|
+
*/
|
|
1037
|
+
export async function generateFullAgents(config, projectRoot = process.cwd()) {
|
|
1038
|
+
// Always use lean template — the procedural 6k-line output is deprecated.
|
|
1039
|
+
return await generateLeanAgents(config, projectRoot);
|
|
1040
|
+
}
|
|
1041
|
+
//# sourceMappingURL=generator.js.map
|