openplanr 0.8.0 → 1.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.
- package/README.md +142 -52
- package/dist/agents/index.d.ts +1 -5
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +1 -4
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/task-parser.d.ts +4 -1
- package/dist/agents/task-parser.d.ts.map +1 -1
- package/dist/agents/task-parser.js +6 -3
- package/dist/agents/task-parser.js.map +1 -1
- package/dist/agents/utils.d.ts +0 -4
- package/dist/agents/utils.d.ts.map +1 -1
- package/dist/agents/utils.js +3 -24
- package/dist/agents/utils.js.map +1 -1
- package/dist/ai/codebase/context-builder.d.ts +22 -3
- package/dist/ai/codebase/context-builder.d.ts.map +1 -1
- package/dist/ai/codebase/context-builder.js +202 -14
- package/dist/ai/codebase/context-builder.js.map +1 -1
- package/dist/ai/codebase/file-reader.d.ts.map +1 -1
- package/dist/ai/codebase/file-reader.js +7 -3
- package/dist/ai/codebase/file-reader.js.map +1 -1
- package/dist/ai/codebase/index.d.ts +3 -1
- package/dist/ai/codebase/index.d.ts.map +1 -1
- package/dist/ai/codebase/index.js +3 -1
- package/dist/ai/codebase/index.js.map +1 -1
- package/dist/ai/codebase/pattern-rules.d.ts +28 -0
- package/dist/ai/codebase/pattern-rules.d.ts.map +1 -0
- package/dist/ai/codebase/pattern-rules.js +186 -0
- package/dist/ai/codebase/pattern-rules.js.map +1 -0
- package/dist/ai/codebase/rules-reader.d.ts +14 -0
- package/dist/ai/codebase/rules-reader.d.ts.map +1 -0
- package/dist/ai/codebase/rules-reader.js +25 -0
- package/dist/ai/codebase/rules-reader.js.map +1 -0
- package/dist/ai/codebase/stack-detector.d.ts.map +1 -1
- package/dist/ai/codebase/stack-detector.js +4 -1
- package/dist/ai/codebase/stack-detector.js.map +1 -1
- package/dist/ai/codebase/tree-generator.d.ts.map +1 -1
- package/dist/ai/codebase/tree-generator.js +5 -2
- package/dist/ai/codebase/tree-generator.js.map +1 -1
- package/dist/ai/errors.js +1 -1
- package/dist/ai/errors.js.map +1 -1
- package/dist/ai/prompts/prompt-builder.d.ts +12 -0
- package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
- package/dist/ai/prompts/prompt-builder.js +45 -3
- package/dist/ai/prompts/prompt-builder.js.map +1 -1
- package/dist/ai/prompts/system-prompts.d.ts +5 -3
- package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
- package/dist/ai/prompts/system-prompts.js +74 -13
- package/dist/ai/prompts/system-prompts.js.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.d.ts +48 -2
- package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.js +19 -0
- package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
- package/dist/ai/types.d.ts +4 -2
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js +3 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/ai/validation/dependency-chains.d.ts +21 -0
- package/dist/ai/validation/dependency-chains.d.ts.map +1 -0
- package/dist/ai/validation/dependency-chains.js +114 -0
- package/dist/ai/validation/dependency-chains.js.map +1 -0
- package/dist/ai/validation/index.d.ts +3 -0
- package/dist/ai/validation/index.d.ts.map +1 -0
- package/dist/ai/validation/index.js +3 -0
- package/dist/ai/validation/index.js.map +1 -0
- package/dist/ai/validation/task-validator.d.ts +37 -0
- package/dist/ai/validation/task-validator.d.ts.map +1 -0
- package/dist/ai/validation/task-validator.js +89 -0
- package/dist/ai/validation/task-validator.js.map +1 -0
- package/dist/cli/commands/backlog.d.ts +10 -0
- package/dist/cli/commands/backlog.d.ts.map +1 -0
- package/dist/cli/commands/backlog.js +292 -0
- package/dist/cli/commands/backlog.js.map +1 -0
- package/dist/cli/commands/checklist.js +4 -4
- package/dist/cli/commands/checklist.js.map +1 -1
- package/dist/cli/commands/config.js +13 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/epic.d.ts.map +1 -1
- package/dist/cli/commands/epic.js +41 -22
- package/dist/cli/commands/epic.js.map +1 -1
- package/dist/cli/commands/estimate.d.ts.map +1 -1
- package/dist/cli/commands/estimate.js +40 -39
- package/dist/cli/commands/estimate.js.map +1 -1
- package/dist/cli/commands/export.d.ts +8 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +282 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/feature.js +9 -9
- package/dist/cli/commands/feature.js.map +1 -1
- package/dist/cli/commands/github.d.ts +8 -0
- package/dist/cli/commands/github.d.ts.map +1 -0
- package/dist/cli/commands/github.js +415 -0
- package/dist/cli/commands/github.js.map +1 -0
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +104 -50
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/quick.d.ts.map +1 -1
- package/dist/cli/commands/quick.js +37 -107
- package/dist/cli/commands/quick.js.map +1 -1
- package/dist/cli/commands/refine.js +21 -21
- package/dist/cli/commands/refine.js.map +1 -1
- package/dist/cli/commands/search.d.ts.map +1 -1
- package/dist/cli/commands/search.js +18 -7
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts +9 -0
- package/dist/cli/commands/sprint.d.ts.map +1 -0
- package/dist/cli/commands/sprint.js +519 -0
- package/dist/cli/commands/sprint.js.map +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +77 -32
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/story.js +15 -15
- package/dist/cli/commands/story.js.map +1 -1
- package/dist/cli/commands/sync.js +11 -7
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/commands/task.d.ts +0 -2
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +14 -169
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/template.d.ts +10 -0
- package/dist/cli/commands/template.d.ts.map +1 -0
- package/dist/cli/commands/template.js +269 -0
- package/dist/cli/commands/template.js.map +1 -0
- package/dist/cli/helpers/task-creation.d.ts +89 -0
- package/dist/cli/helpers/task-creation.d.ts.map +1 -0
- package/dist/cli/helpers/task-creation.js +140 -0
- package/dist/cli/helpers/task-creation.js.map +1 -0
- package/dist/cli/index.js +29 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/models/schema.d.ts +2 -0
- package/dist/models/schema.d.ts.map +1 -1
- package/dist/models/schema.js +2 -0
- package/dist/models/schema.js.map +1 -1
- package/dist/models/types.d.ts +32 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/services/artifact-gathering.d.ts +2 -0
- package/dist/services/artifact-gathering.d.ts.map +1 -1
- package/dist/services/artifact-gathering.js +26 -7
- package/dist/services/artifact-gathering.js.map +1 -1
- package/dist/services/artifact-service.d.ts +5 -5
- package/dist/services/artifact-service.d.ts.map +1 -1
- package/dist/services/artifact-service.js +4 -0
- package/dist/services/artifact-service.js.map +1 -1
- package/dist/services/config-service.d.ts.map +1 -1
- package/dist/services/config-service.js +2 -0
- package/dist/services/config-service.js.map +1 -1
- package/dist/services/credential-backends.d.ts.map +1 -1
- package/dist/services/credential-backends.js +15 -7
- package/dist/services/credential-backends.js.map +1 -1
- package/dist/services/credentials-service.d.ts.map +1 -1
- package/dist/services/credentials-service.js +6 -3
- package/dist/services/credentials-service.js.map +1 -1
- package/dist/services/github-service.d.ts +83 -0
- package/dist/services/github-service.d.ts.map +1 -0
- package/dist/services/github-service.js +440 -0
- package/dist/services/github-service.js.map +1 -0
- package/dist/services/template-service.d.ts +2 -1
- package/dist/services/template-service.d.ts.map +1 -1
- package/dist/services/template-service.js +3 -1
- package/dist/services/template-service.js.map +1 -1
- package/dist/templates/backlog/backlog-item.md.hbs +40 -0
- package/dist/templates/checklists/agile-checklist.md.hbs +1 -1
- package/dist/templates/export/planning-report.html.hbs +230 -0
- package/dist/templates/export/planning-report.md.hbs +136 -0
- package/dist/templates/quick/quick-task.md.hbs +1 -1
- package/dist/templates/rules/claude/CLAUDE.md.hbs +78 -35
- package/dist/templates/rules/codex/AGENTS.md.hbs +73 -17
- package/dist/templates/rules/cursor/2101-implement-task-list.mdc.hbs +66 -14
- package/dist/templates/sprints/sprint.md.hbs +42 -0
- package/dist/templates/task-templates/api-integration.json +45 -0
- package/dist/templates/task-templates/auth-flow.json +48 -0
- package/dist/templates/task-templates/database-migration.json +44 -0
- package/dist/templates/task-templates/react-component.json +45 -0
- package/dist/templates/task-templates/rest-endpoint.json +53 -0
- package/dist/templates/tasks/task-list.md.hbs +1 -1
- package/dist/utils/constants.d.ts +4 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +4 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/logger.d.ts +31 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +92 -9
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/markdown.d.ts +3 -2
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js +3 -1
- package/dist/utils/markdown.js.map +1 -1
- package/dist/utils/slugify.d.ts +8 -1
- package/dist/utils/slugify.d.ts.map +1 -1
- package/dist/utils/slugify.js +18 -2
- package/dist/utils/slugify.js.map +1 -1
- package/package.json +14 -3
- package/dist/agents/agent-factory.d.ts +0 -7
- package/dist/agents/agent-factory.d.ts.map +0 -1
- package/dist/agents/agent-factory.js +0 -22
- package/dist/agents/agent-factory.js.map +0 -1
- package/dist/agents/claude-agent.d.ts +0 -18
- package/dist/agents/claude-agent.d.ts.map +0 -1
- package/dist/agents/claude-agent.js +0 -183
- package/dist/agents/claude-agent.js.map +0 -1
- package/dist/agents/codex-agent.d.ts +0 -17
- package/dist/agents/codex-agent.d.ts.map +0 -1
- package/dist/agents/codex-agent.js +0 -124
- package/dist/agents/codex-agent.js.map +0 -1
- package/dist/agents/cursor-agent.d.ts +0 -14
- package/dist/agents/cursor-agent.d.ts.map +0 -1
- package/dist/agents/cursor-agent.js +0 -49
- package/dist/agents/cursor-agent.js.map +0 -1
- package/dist/agents/implementation-bridge.d.ts +0 -30
- package/dist/agents/implementation-bridge.d.ts.map +0 -1
- package/dist/agents/implementation-bridge.js +0 -256
- package/dist/agents/implementation-bridge.js.map +0 -1
- package/dist/agents/progress.d.ts +0 -62
- package/dist/agents/progress.d.ts.map +0 -1
- package/dist/agents/progress.js +0 -155
- package/dist/agents/progress.js.map +0 -1
- package/dist/agents/prompt-composer.d.ts +0 -30
- package/dist/agents/prompt-composer.d.ts.map +0 -1
- package/dist/agents/prompt-composer.js +0 -81
- package/dist/agents/prompt-composer.js.map +0 -1
- package/dist/agents/types.d.ts +0 -25
- package/dist/agents/types.d.ts.map +0 -1
- package/dist/agents/types.js +0 -8
- package/dist/agents/types.js.map +0 -1
- package/dist/utils/error-context.d.ts +0 -23
- package/dist/utils/error-context.d.ts.map +0 -1
- package/dist/utils/error-context.js +0 -94
- package/dist/utils/error-context.js.map +0 -1
|
@@ -1,14 +1,161 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Orchestrates codebase awareness into a single context string.
|
|
3
3
|
*
|
|
4
|
-
* Combines tech stack detection, folder tree,
|
|
5
|
-
* into a formatted block for
|
|
6
|
-
*
|
|
4
|
+
* Combines tech stack detection, folder tree, architecture files,
|
|
5
|
+
* and keyword-matched file snippets into a formatted block for
|
|
6
|
+
* inclusion in AI prompts. Respects a token budget to avoid overflow.
|
|
7
|
+
*
|
|
8
|
+
* Architecture files are always included — they define the patterns
|
|
9
|
+
* the AI must follow when generating implementation tasks.
|
|
7
10
|
*/
|
|
8
|
-
import {
|
|
11
|
+
import { readdir } from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { logger } from '../../utils/logger.js';
|
|
14
|
+
import { findRelatedFiles, readFileSnippets, readProjectFile } from './file-reader.js';
|
|
15
|
+
import { detectPatternRules } from './pattern-rules.js';
|
|
16
|
+
import { readProjectRules } from './rules-reader.js';
|
|
9
17
|
import { detectTechStack, formatTechStack } from './stack-detector.js';
|
|
10
18
|
import { generateFolderTree } from './tree-generator.js';
|
|
11
|
-
const MAX_CONTEXT_CHARS =
|
|
19
|
+
const MAX_CONTEXT_CHARS = 48_000; // ~12K tokens (increased for architecture context)
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Architecture file discovery
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Well-known file patterns that define a project's architecture.
|
|
25
|
+
* Ordered by priority — higher entries are included first when budget is tight.
|
|
26
|
+
*/
|
|
27
|
+
const ARCHITECTURE_PATTERNS = [
|
|
28
|
+
{
|
|
29
|
+
candidates: ['src/models/types.ts', 'src/types/index.ts', 'src/types.ts'],
|
|
30
|
+
label: 'Core type definitions — ALL interfaces, enums, and type aliases used across the project',
|
|
31
|
+
budget: 4_000,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
candidates: [
|
|
35
|
+
'src/services/artifact-service.ts',
|
|
36
|
+
'src/services/crud-service.ts',
|
|
37
|
+
'src/services/data-service.ts',
|
|
38
|
+
],
|
|
39
|
+
label: 'Main CRUD service — how entities are created, read, listed, and updated',
|
|
40
|
+
budget: 3_000,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
candidates: ['src/services/id-service.ts', 'src/utils/id.ts'],
|
|
44
|
+
label: 'ID generation — how unique IDs are assigned to new entities',
|
|
45
|
+
budget: 2_000,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
candidates: ['src/cli/index.ts', 'src/index.ts', 'src/main.ts', 'src/app.ts'],
|
|
49
|
+
label: 'Entry point — how commands/routes are registered and wired together',
|
|
50
|
+
budget: 2_000,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
candidates: [
|
|
54
|
+
'src/cli/commands/quick.ts',
|
|
55
|
+
'src/cli/commands/task.ts',
|
|
56
|
+
'src/cli/commands/epic.ts',
|
|
57
|
+
],
|
|
58
|
+
label: 'Example command — the pattern every new command should follow',
|
|
59
|
+
budget: 3_000,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
candidates: ['src/services/config-service.ts', 'src/config.ts'],
|
|
63
|
+
label: 'Configuration — how project config is loaded and validated',
|
|
64
|
+
budget: 2_000,
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* Discover architecture files that exist in the project.
|
|
69
|
+
* Tries each candidate path per pattern — first match wins.
|
|
70
|
+
* Returns a map of relative paths → labeled, truncated content.
|
|
71
|
+
*/
|
|
72
|
+
export async function findArchitectureFiles(projectDir) {
|
|
73
|
+
const result = new Map();
|
|
74
|
+
for (const pattern of ARCHITECTURE_PATTERNS) {
|
|
75
|
+
for (const candidate of pattern.candidates) {
|
|
76
|
+
const content = await readProjectFile(projectDir, candidate);
|
|
77
|
+
if (content) {
|
|
78
|
+
const truncated = content.slice(0, pattern.budget);
|
|
79
|
+
result.set(candidate, `// ${pattern.label}\n${truncated}`);
|
|
80
|
+
break; // First match wins for this pattern
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Source file inventory
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
/**
|
|
90
|
+
* List all source files in key directories (services, commands, models, etc).
|
|
91
|
+
* Returns a compact string the AI can use to verify file paths exist.
|
|
92
|
+
* Unlike the folder tree, this is NEVER truncated — it's the source of truth.
|
|
93
|
+
*/
|
|
94
|
+
async function buildSourceInventory(projectDir) {
|
|
95
|
+
// Discover all src/ subdirectories dynamically instead of a hardcoded list
|
|
96
|
+
const srcDir = path.join(projectDir, 'src');
|
|
97
|
+
let topLevelDirs = [];
|
|
98
|
+
try {
|
|
99
|
+
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
100
|
+
topLevelDirs = entries
|
|
101
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.'))
|
|
102
|
+
.map((e) => `src/${e.name}`);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
logger.debug('Failed to read src directory for inventory', err);
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
// Expand into leaf directories (one level deep for nested dirs like src/ai/prompts)
|
|
109
|
+
const keyDirs = [];
|
|
110
|
+
for (const dir of topLevelDirs) {
|
|
111
|
+
const fullDir = path.join(projectDir, dir);
|
|
112
|
+
try {
|
|
113
|
+
const entries = await readdir(fullDir, { withFileTypes: true });
|
|
114
|
+
const hasSubDirs = entries.some((e) => e.isDirectory() && !e.name.startsWith('.'));
|
|
115
|
+
if (hasSubDirs) {
|
|
116
|
+
// Add subdirectories (e.g., src/ai/prompts, src/ai/schemas)
|
|
117
|
+
for (const e of entries) {
|
|
118
|
+
if (e.isDirectory() && !e.name.startsWith('.')) {
|
|
119
|
+
keyDirs.push(`${dir}/${e.name}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Also add files directly in this dir (e.g., src/ai/types.ts)
|
|
123
|
+
const hasFiles = entries.some((e) => e.isFile() && !e.name.startsWith('.'));
|
|
124
|
+
if (hasFiles)
|
|
125
|
+
keyDirs.push(dir);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
keyDirs.push(dir);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
logger.debug('Failed to expand subdirectories for inventory', err);
|
|
133
|
+
keyDirs.push(dir);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const lines = [];
|
|
137
|
+
for (const dir of keyDirs.sort()) {
|
|
138
|
+
const fullDir = path.join(projectDir, dir);
|
|
139
|
+
try {
|
|
140
|
+
const entries = await readdir(fullDir, { withFileTypes: true });
|
|
141
|
+
const files = entries
|
|
142
|
+
.filter((e) => e.isFile() && !e.name.startsWith('.'))
|
|
143
|
+
.map((e) => e.name)
|
|
144
|
+
.sort();
|
|
145
|
+
if (files.length > 0) {
|
|
146
|
+
lines.push(`${dir}/: ${files.join(', ')}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
logger.debug('Failed to list directory files for inventory', err);
|
|
151
|
+
// Directory doesn't exist, skip
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return lines.join('\n');
|
|
155
|
+
}
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Public API
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
12
159
|
/**
|
|
13
160
|
* Build a complete codebase context for AI prompt enrichment.
|
|
14
161
|
*
|
|
@@ -16,13 +163,29 @@ const MAX_CONTEXT_CHARS = 32_000; // ~8K tokens
|
|
|
16
163
|
* @param keywords - Keywords to find related files (extracted from task/story)
|
|
17
164
|
*/
|
|
18
165
|
export async function buildCodebaseContext(projectDir, keywords = []) {
|
|
19
|
-
const [techStack, folderTree, relatedPaths] = await Promise.all([
|
|
166
|
+
const [techStack, folderTree, sourceInventory, relatedPaths, architectureFiles, projectRules] = await Promise.all([
|
|
20
167
|
detectTechStack(projectDir),
|
|
21
168
|
generateFolderTree(projectDir, 3),
|
|
169
|
+
buildSourceInventory(projectDir),
|
|
22
170
|
findRelatedFiles(projectDir, keywords, 8),
|
|
171
|
+
findArchitectureFiles(projectDir),
|
|
172
|
+
readProjectRules(projectDir),
|
|
23
173
|
]);
|
|
24
|
-
|
|
25
|
-
|
|
174
|
+
// Detect patterns from architecture files (sync, fast)
|
|
175
|
+
const patternRules = detectPatternRules(architectureFiles, sourceInventory);
|
|
176
|
+
// Remove architecture files from keyword results to avoid duplicates
|
|
177
|
+
const archPaths = new Set(architectureFiles.keys());
|
|
178
|
+
const filteredRelated = relatedPaths.filter((p) => !archPaths.has(p));
|
|
179
|
+
const relatedFiles = await readFileSnippets(projectDir, filteredRelated, 12_000);
|
|
180
|
+
return {
|
|
181
|
+
techStack,
|
|
182
|
+
folderTree,
|
|
183
|
+
sourceInventory,
|
|
184
|
+
architectureFiles,
|
|
185
|
+
relatedFiles,
|
|
186
|
+
projectRules,
|
|
187
|
+
patternRules,
|
|
188
|
+
};
|
|
26
189
|
}
|
|
27
190
|
/**
|
|
28
191
|
* Format the codebase context into a prompt-friendly string.
|
|
@@ -30,11 +193,32 @@ export async function buildCodebaseContext(projectDir, keywords = []) {
|
|
|
30
193
|
*/
|
|
31
194
|
export function formatCodebaseContext(ctx) {
|
|
32
195
|
const sections = [];
|
|
196
|
+
// Priority 0: User-defined project rules (always included, never dropped)
|
|
197
|
+
if (ctx.projectRules) {
|
|
198
|
+
sections.push(`## Project Rules (MANDATORY — follow these exactly)\n${ctx.projectRules}`);
|
|
199
|
+
}
|
|
33
200
|
// Priority 1: Tech stack (always included, small)
|
|
34
201
|
if (ctx.techStack) {
|
|
35
202
|
sections.push(`## Tech Stack\n${formatTechStack(ctx.techStack)}`);
|
|
36
203
|
}
|
|
37
|
-
// Priority 2:
|
|
204
|
+
// Priority 2: Architecture files (always included — defines project patterns)
|
|
205
|
+
if (ctx.architectureFiles.size > 0) {
|
|
206
|
+
const archBlocks = [];
|
|
207
|
+
for (const [filePath, content] of ctx.architectureFiles) {
|
|
208
|
+
archBlocks.push(`### ${filePath}\n\`\`\`\n${content}\n\`\`\``);
|
|
209
|
+
}
|
|
210
|
+
sections.push(`## Architecture (IMPORTANT: follow these patterns)\n${archBlocks.join('\n\n')}`);
|
|
211
|
+
}
|
|
212
|
+
// Priority 2.5: Auto-detected pattern rules
|
|
213
|
+
if (ctx.patternRules.length > 0) {
|
|
214
|
+
const ruleBlocks = ctx.patternRules.map((r) => `### ${r.name}\n**Rule:** ${r.rule}\n**Anti-pattern:** ${r.antiPattern}\n**Evidence:** ${r.evidence.join(', ')}`);
|
|
215
|
+
sections.push(`## Detected Project Patterns (MUST follow)\n${ruleBlocks.join('\n\n')}`);
|
|
216
|
+
}
|
|
217
|
+
// Priority 3: Source file inventory (compact, may be truncated by final budget cap)
|
|
218
|
+
if (ctx.sourceInventory) {
|
|
219
|
+
sections.push(`## Existing Source Files (ONLY reference files listed here or follow their naming pattern)\n${ctx.sourceInventory}`);
|
|
220
|
+
}
|
|
221
|
+
// Priority 4: Folder tree (truncated if needed)
|
|
38
222
|
if (ctx.folderTree) {
|
|
39
223
|
const treeLines = ctx.folderTree.split('\n');
|
|
40
224
|
const maxLines = 60;
|
|
@@ -43,7 +227,7 @@ export function formatCodebaseContext(ctx) {
|
|
|
43
227
|
: ctx.folderTree;
|
|
44
228
|
sections.push(`## Project Structure\n\`\`\`\n${truncatedTree}\n\`\`\``);
|
|
45
229
|
}
|
|
46
|
-
// Priority
|
|
230
|
+
// Priority 5: Keyword-matched file snippets (dropped first if over budget)
|
|
47
231
|
if (ctx.relatedFiles.size > 0) {
|
|
48
232
|
const fileBlocks = [];
|
|
49
233
|
for (const [filePath, content] of ctx.relatedFiles) {
|
|
@@ -51,14 +235,18 @@ export function formatCodebaseContext(ctx) {
|
|
|
51
235
|
}
|
|
52
236
|
sections.push(`## Related Files\n${fileBlocks.join('\n\n')}`);
|
|
53
237
|
}
|
|
54
|
-
// Apply budget
|
|
238
|
+
// Apply budget — drop from the end (lowest priority first)
|
|
239
|
+
// Possible sections (some may be absent): rules, tech stack, architecture, inventory, tree, related files
|
|
55
240
|
let result = sections.join('\n\n');
|
|
56
241
|
if (result.length > MAX_CONTEXT_CHARS) {
|
|
57
|
-
// Drop
|
|
58
|
-
result = sections.slice(0,
|
|
242
|
+
// Drop related files first (last section)
|
|
243
|
+
result = sections.slice(0, -1).join('\n\n');
|
|
244
|
+
}
|
|
245
|
+
if (result.length > MAX_CONTEXT_CHARS) {
|
|
246
|
+
// Drop tree too (second-to-last remaining)
|
|
247
|
+
result = sections.slice(0, -2).join('\n\n');
|
|
59
248
|
}
|
|
60
249
|
if (result.length > MAX_CONTEXT_CHARS) {
|
|
61
|
-
// Even tree is too large, truncate aggressively
|
|
62
250
|
result = `${result.slice(0, MAX_CONTEXT_CHARS)}\n... (context truncated)`;
|
|
63
251
|
}
|
|
64
252
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../../src/ai/codebase/context-builder.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../../src/ai/codebase/context-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC,mDAAmD;AAiBrF,8EAA8E;AAC9E,8BAA8B;AAC9B,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,qBAAqB,GAOtB;IACH;QACE,UAAU,EAAE,CAAC,qBAAqB,EAAE,oBAAoB,EAAE,cAAc,CAAC;QACzE,KAAK,EACH,yFAAyF;QAC3F,MAAM,EAAE,KAAK;KACd;IACD;QACE,UAAU,EAAE;YACV,kCAAkC;YAClC,8BAA8B;YAC9B,8BAA8B;SAC/B;QACD,KAAK,EAAE,yEAAyE;QAChF,MAAM,EAAE,KAAK;KACd;IACD;QACE,UAAU,EAAE,CAAC,4BAA4B,EAAE,iBAAiB,CAAC;QAC7D,KAAK,EAAE,6DAA6D;QACpE,MAAM,EAAE,KAAK;KACd;IACD;QACE,UAAU,EAAE,CAAC,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,CAAC;QAC7E,KAAK,EAAE,qEAAqE;QAC5E,MAAM,EAAE,KAAK;KACd;IACD;QACE,UAAU,EAAE;YACV,2BAA2B;YAC3B,0BAA0B;YAC1B,0BAA0B;SAC3B;QACD,KAAK,EAAE,+DAA+D;QACtE,MAAM,EAAE,KAAK;KACd;IACD;QACE,UAAU,EAAE,CAAC,gCAAgC,EAAE,eAAe,CAAC;QAC/D,KAAK,EAAE,4DAA4D;QACnE,MAAM,EAAE,KAAK;KACd;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,UAAkB;IAC5D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,KAAK,MAAM,OAAO,IAAI,qBAAqB,EAAE,CAAC;QAC5C,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YAC7D,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBACnD,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC,CAAC;gBAC3D,MAAM,CAAC,oCAAoC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;GAIG;AACH,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IACpD,2EAA2E;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,YAAY,GAAa,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,YAAY,GAAG,OAAO;aACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;aACzD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,oFAAoF;IACpF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YACnF,IAAI,UAAU,EAAE,CAAC;gBACf,4DAA4D;gBAC5D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;oBACxB,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC/C,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;gBACD,8DAA8D;gBAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC5E,IAAI,QAAQ;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,OAAO;iBAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;iBACpD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAClB,IAAI,EAAE,CAAC;YACV,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,8CAA8C,EAAE,GAAG,CAAC,CAAC;YAClE,gCAAgC;QAClC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAkB,EAClB,WAAqB,EAAE;IAEvB,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,CAAC,GAC3F,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,eAAe,CAAC,UAAU,CAAC;QAC3B,kBAAkB,CAAC,UAAU,EAAE,CAAC,CAAC;QACjC,oBAAoB,CAAC,UAAU,CAAC;QAChC,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzC,qBAAqB,CAAC,UAAU,CAAC;QACjC,gBAAgB,CAAC,UAAU,CAAC;KAC7B,CAAC,CAAC;IAEL,uDAAuD;IACvD,MAAM,YAAY,GAAG,kBAAkB,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;IAE5E,qEAAqE;IACrE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtE,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;IAEjF,OAAO;QACL,SAAS;QACT,UAAU;QACV,eAAe;QACf,iBAAiB;QACjB,YAAY;QACZ,YAAY;QACZ,YAAY;KACb,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAoB;IACxD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,0EAA0E;IAC1E,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,wDAAwD,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,kDAAkD;IAClD,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,kBAAkB,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,8EAA8E;IAC9E,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACxD,UAAU,CAAC,IAAI,CAAC,OAAO,QAAQ,aAAa,OAAO,UAAU,CAAC,CAAC;QACjE,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,uDAAuD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,4CAA4C;IAC5C,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CACrC,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,IAAI,uBAAuB,CAAC,CAAC,WAAW,mBAAmB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnH,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,+CAA+C,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,oFAAoF;IACpF,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CACX,+FAA+F,GAAG,CAAC,eAAe,EAAE,CACrH,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,MAAM,aAAa,GACjB,SAAS,CAAC,MAAM,GAAG,QAAQ;YACzB,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB;YAC/D,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,iCAAiC,aAAa,UAAU,CAAC,CAAC;IAC1E,CAAC;IAED,2EAA2E;IAC3E,IAAI,GAAG,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;YACnD,UAAU,CAAC,IAAI,CAAC,OAAO,QAAQ,aAAa,OAAO,UAAU,CAAC,CAAC;QACjE,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,qBAAqB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,2DAA2D;IAC3D,0GAA0G;IAC1G,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACtC,0CAA0C;QAC1C,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACtC,2CAA2C;QAC3C,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,2BAA2B,CAAC;IAC5E,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,qBAAqB;IACrB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,oDAAoD;IACpD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,IAAI,EAAE,CAAC;IACtF,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,uBAAuB;IACvB,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;IAClE,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC1C,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-reader.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/file-reader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"file-reader.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/file-reader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqDH;;;GAGG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWxB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,GAAE,MAAW,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAqDD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EAAE,EACvB,WAAW,GAAE,MAAe,GAC3B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgB9B"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
+
import { logger } from '../../utils/logger.js';
|
|
9
10
|
const MAX_FILE_SIZE = 50_000; // 50KB per file
|
|
10
11
|
const MAX_SNIPPET_CHARS = 3_000; // Truncate snippets to this length
|
|
11
12
|
const SOURCE_EXTENSIONS = new Set([
|
|
@@ -62,7 +63,8 @@ export async function readProjectFile(projectDir, relativePath) {
|
|
|
62
63
|
return null;
|
|
63
64
|
return await readFile(fullPath, 'utf-8');
|
|
64
65
|
}
|
|
65
|
-
catch {
|
|
66
|
+
catch (err) {
|
|
67
|
+
logger.debug('Failed to read project file', err);
|
|
66
68
|
return null;
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -85,7 +87,8 @@ async function searchDir(rootDir, currentDir, keywords, matches, maxResults, dep
|
|
|
85
87
|
try {
|
|
86
88
|
entries = await readdir(currentDir);
|
|
87
89
|
}
|
|
88
|
-
catch {
|
|
90
|
+
catch (err) {
|
|
91
|
+
logger.debug('Failed to read directory during file search', err);
|
|
89
92
|
return;
|
|
90
93
|
}
|
|
91
94
|
for (const entry of entries) {
|
|
@@ -109,7 +112,8 @@ async function searchDir(rootDir, currentDir, keywords, matches, maxResults, dep
|
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
|
-
catch {
|
|
115
|
+
catch (err) {
|
|
116
|
+
logger.debug('Failed to stat file entry', err);
|
|
113
117
|
// Skip inaccessible entries
|
|
114
118
|
}
|
|
115
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-reader.js","sourceRoot":"","sources":["../../../src/ai/codebase/file-reader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"file-reader.js","sourceRoot":"","sources":["../../../src/ai/codebase/file-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { buildCodebaseContext, type CodebaseContext, extractKeywords, formatCodebaseContext, } from './context-builder.js';
|
|
1
|
+
export { buildCodebaseContext, type CodebaseContext, extractKeywords, findArchitectureFiles, formatCodebaseContext, } from './context-builder.js';
|
|
2
2
|
export { findRelatedFiles, readFileSnippets, readProjectFile } from './file-reader.js';
|
|
3
|
+
export { detectPatternRules, type PatternRule } from './pattern-rules.js';
|
|
4
|
+
export { readProjectRules } from './rules-reader.js';
|
|
3
5
|
export { detectTechStack, formatTechStack, type TechStack } from './stack-detector.js';
|
|
4
6
|
export { generateFolderTree } from './tree-generator.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,eAAe,EACf,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { buildCodebaseContext, extractKeywords, formatCodebaseContext, } from './context-builder.js';
|
|
1
|
+
export { buildCodebaseContext, extractKeywords, findArchitectureFiles, formatCodebaseContext, } from './context-builder.js';
|
|
2
2
|
export { findRelatedFiles, readFileSnippets, readProjectFile } from './file-reader.js';
|
|
3
|
+
export { detectPatternRules } from './pattern-rules.js';
|
|
4
|
+
export { readProjectRules } from './rules-reader.js';
|
|
3
5
|
export { detectTechStack, formatTechStack } from './stack-detector.js';
|
|
4
6
|
export { generateFolderTree } from './tree-generator.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/codebase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAEpB,eAAe,EACf,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/codebase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAEpB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic-based pattern detection from architecture files.
|
|
3
|
+
*
|
|
4
|
+
* Produces human-readable rules that are injected into AI prompts
|
|
5
|
+
* to prevent common mistakes like creating parallel CRUD services,
|
|
6
|
+
* forgetting to register commands, or scattering type definitions.
|
|
7
|
+
*
|
|
8
|
+
* Every detector is a pure function — fast, deterministic, no AI.
|
|
9
|
+
*/
|
|
10
|
+
export interface PatternRule {
|
|
11
|
+
/** Short identifier (e.g., "generic-crud"). */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Rule text injected into the prompt. */
|
|
14
|
+
rule: string;
|
|
15
|
+
/** Which file(s) this was detected from. */
|
|
16
|
+
evidence: string[];
|
|
17
|
+
/** What NOT to do — helps the AI avoid common mistakes. */
|
|
18
|
+
antiPattern: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Detect architectural patterns from architecture file contents.
|
|
22
|
+
* Returns rules the AI should follow when generating tasks.
|
|
23
|
+
*
|
|
24
|
+
* @param architectureFiles - Map of relative path → labeled content (from findArchitectureFiles)
|
|
25
|
+
* @param sourceInventory - Compact source listing (from buildSourceInventory)
|
|
26
|
+
*/
|
|
27
|
+
export declare function detectPatternRules(architectureFiles: Map<string, string>, sourceInventory: string): PatternRule[];
|
|
28
|
+
//# sourceMappingURL=pattern-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-rules.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/pattern-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;CACrB;AAkKD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,eAAe,EAAE,MAAM,GACtB,WAAW,EAAE,CA0Bf"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic-based pattern detection from architecture files.
|
|
3
|
+
*
|
|
4
|
+
* Produces human-readable rules that are injected into AI prompts
|
|
5
|
+
* to prevent common mistakes like creating parallel CRUD services,
|
|
6
|
+
* forgetting to register commands, or scattering type definitions.
|
|
7
|
+
*
|
|
8
|
+
* Every detector is a pure function — fast, deterministic, no AI.
|
|
9
|
+
*/
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Utility helpers
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/** Extract exported function names from TypeScript/JavaScript source. */
|
|
14
|
+
function extractExportedFunctions(content) {
|
|
15
|
+
return [...content.matchAll(/export\s+(?:async\s+)?function\s+(\w+)/g)].map((m) => m[1]);
|
|
16
|
+
}
|
|
17
|
+
/** Extract exported type/interface names from TypeScript source. */
|
|
18
|
+
function extractExportedTypes(content) {
|
|
19
|
+
return [...content.matchAll(/export\s+(?:type|interface)\s+(\w+)/g)].map((m) => m[1]);
|
|
20
|
+
}
|
|
21
|
+
/** Count individual files matching a pattern in the source inventory. */
|
|
22
|
+
function countInventoryMatches(inventory, pattern) {
|
|
23
|
+
let count = 0;
|
|
24
|
+
for (const line of inventory.split('\n')) {
|
|
25
|
+
const colonIdx = line.indexOf(':');
|
|
26
|
+
if (colonIdx === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const fileList = line.slice(colonIdx + 1);
|
|
29
|
+
for (const file of fileList.split(',')) {
|
|
30
|
+
if (pattern.test(file.trim()))
|
|
31
|
+
count++;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return count;
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Pattern detectors
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Detect a generic CRUD service pattern.
|
|
41
|
+
*
|
|
42
|
+
* If the service exports only generic functions (create, read, list, update,
|
|
43
|
+
* delete) that take a `type` parameter and no entity-specific variants like
|
|
44
|
+
* `createUser()`, emit a rule forbidding entity-specific services.
|
|
45
|
+
*/
|
|
46
|
+
function detectGenericCRUD(filePath, content) {
|
|
47
|
+
const fns = extractExportedFunctions(content);
|
|
48
|
+
if (fns.length === 0)
|
|
49
|
+
return null;
|
|
50
|
+
const crudNames = /^(create|read|list|update|delete|get|find|remove)/i;
|
|
51
|
+
const crudFns = fns.filter((f) => crudNames.test(f));
|
|
52
|
+
if (crudFns.length < 2)
|
|
53
|
+
return null;
|
|
54
|
+
// Check if functions are entity-specific (createUser, deleteOrder) vs generic
|
|
55
|
+
// Generic names use abstract nouns: Artifact, Entry, Item, Record, Entity, Resource, Document, Object
|
|
56
|
+
const genericSuffixes = /^(create|read|list|update|delete|get|find|remove)(Artifact|Entry|Item|Record|Entity|Resource|Document|Object|Many|All|By)/i;
|
|
57
|
+
const entitySpecific = /^(create|read|list|update|delete|get|find|remove)[A-Z][a-z]{3,}/;
|
|
58
|
+
const hasEntitySpecific = crudFns.some((f) => entitySpecific.test(f) && !genericSuffixes.test(f));
|
|
59
|
+
if (hasEntitySpecific)
|
|
60
|
+
return null;
|
|
61
|
+
return {
|
|
62
|
+
name: 'generic-crud',
|
|
63
|
+
rule: `This project uses a generic CRUD service (${filePath}). All entity operations go through the generic functions: ${crudFns.join(', ')}. Business logic lives in command files or dedicated orchestration modules, NOT in this service.`,
|
|
64
|
+
evidence: [filePath],
|
|
65
|
+
antiPattern: `Do NOT create entity-specific CRUD functions (e.g., createBacklogItem, deleteUser) in ${filePath}. Use the existing generic functions with the appropriate type parameter.`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Detect a command registration pattern.
|
|
70
|
+
*
|
|
71
|
+
* If the entry point file has `register*Command()` calls, emit a rule
|
|
72
|
+
* requiring new commands to follow the same pattern.
|
|
73
|
+
*/
|
|
74
|
+
function detectCommandRegistration(filePath, content) {
|
|
75
|
+
const registerCalls = content.match(/register\w+Command\s*\(/g);
|
|
76
|
+
if (!registerCalls || registerCalls.length < 2)
|
|
77
|
+
return null;
|
|
78
|
+
const names = registerCalls.map((c) => c.replace(/\s*\($/, ''));
|
|
79
|
+
return {
|
|
80
|
+
name: 'command-registration',
|
|
81
|
+
rule: `New commands MUST be registered in ${filePath} using the register<Name>Command() pattern. Existing registrations: ${names.join(', ')}.`,
|
|
82
|
+
evidence: [filePath],
|
|
83
|
+
antiPattern: `Do NOT create command files without also adding a register*Command() call in ${filePath}. A command file that isn't registered will never be reachable.`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Detect a central types file pattern.
|
|
88
|
+
*
|
|
89
|
+
* If one types file contains 5+ exported types/interfaces and no other
|
|
90
|
+
* type files exist in the source inventory, emit a rule requiring all
|
|
91
|
+
* types to live in that file.
|
|
92
|
+
*/
|
|
93
|
+
function detectCentralTypes(filePath, content, sourceInventory) {
|
|
94
|
+
const types = extractExportedTypes(content);
|
|
95
|
+
if (types.length < 5)
|
|
96
|
+
return null;
|
|
97
|
+
// Check if there are other type files in the inventory
|
|
98
|
+
const otherTypeFiles = countInventoryMatches(sourceInventory, /types\.\w+|interfaces\.\w+/i);
|
|
99
|
+
// The central types file itself counts as 1 match
|
|
100
|
+
if (otherTypeFiles > 1)
|
|
101
|
+
return null;
|
|
102
|
+
return {
|
|
103
|
+
name: 'central-types',
|
|
104
|
+
rule: `All type definitions go in ${filePath} (currently has ${types.length} exports). Do NOT create new type files — add interfaces, enums, and type aliases to this file.`,
|
|
105
|
+
evidence: [filePath],
|
|
106
|
+
antiPattern: `Do NOT create files like types/<entity>.ts or interfaces/<entity>.ts. All types belong in ${filePath}.`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Detect an ID generation pattern.
|
|
111
|
+
*
|
|
112
|
+
* If an id-service exports a function with "id" in its name that accepts
|
|
113
|
+
* a prefix parameter, emit a rule about configuring new prefixes.
|
|
114
|
+
*/
|
|
115
|
+
function detectIDGeneration(filePath, content) {
|
|
116
|
+
const fns = extractExportedFunctions(content);
|
|
117
|
+
const idFn = fns.find((f) => /id/i.test(f) && /next|generate|create/i.test(f));
|
|
118
|
+
if (!idFn)
|
|
119
|
+
return null;
|
|
120
|
+
// Look for prefix-related parameters or constants
|
|
121
|
+
const hasPrefix = /prefix/i.test(content);
|
|
122
|
+
if (!hasPrefix)
|
|
123
|
+
return null;
|
|
124
|
+
return {
|
|
125
|
+
name: 'id-generation',
|
|
126
|
+
rule: `IDs are generated via ${idFn}() in ${filePath} using configurable prefixes. New entity types MUST have their prefix registered in the project config (idPrefix map) and use ${idFn}() for ID assignment.`,
|
|
127
|
+
evidence: [filePath],
|
|
128
|
+
antiPattern: `Do NOT hardcode IDs or create separate ID generation logic. Always use ${idFn}() with the correct prefix.`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Detect a template rendering pattern.
|
|
133
|
+
*
|
|
134
|
+
* If a templates directory contains Handlebars or similar template files,
|
|
135
|
+
* emit a rule requiring new artifact types to have corresponding templates.
|
|
136
|
+
*/
|
|
137
|
+
function detectTemplateRendering(sourceInventory) {
|
|
138
|
+
const templateLines = sourceInventory.split('\n').filter((line) => /templates/i.test(line));
|
|
139
|
+
if (templateLines.length === 0)
|
|
140
|
+
return null;
|
|
141
|
+
const hasHandlebars = templateLines.some((line) => /\.hbs/.test(line));
|
|
142
|
+
if (!hasHandlebars)
|
|
143
|
+
return null;
|
|
144
|
+
return {
|
|
145
|
+
name: 'template-rendering',
|
|
146
|
+
rule: 'This project uses Handlebars templates for artifact generation. New artifact types MUST have a corresponding .md.hbs template in the templates directory.',
|
|
147
|
+
evidence: templateLines.map((l) => l.split(':')[0].trim()),
|
|
148
|
+
antiPattern: 'Do NOT generate markdown directly in code. Create a .md.hbs template and use the template rendering service.',
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Public API
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/**
|
|
155
|
+
* Detect architectural patterns from architecture file contents.
|
|
156
|
+
* Returns rules the AI should follow when generating tasks.
|
|
157
|
+
*
|
|
158
|
+
* @param architectureFiles - Map of relative path → labeled content (from findArchitectureFiles)
|
|
159
|
+
* @param sourceInventory - Compact source listing (from buildSourceInventory)
|
|
160
|
+
*/
|
|
161
|
+
export function detectPatternRules(architectureFiles, sourceInventory) {
|
|
162
|
+
const rules = [];
|
|
163
|
+
for (const [filePath, labeledContent] of architectureFiles) {
|
|
164
|
+
// Strip the label comment line added by findArchitectureFiles
|
|
165
|
+
const content = labeledContent.replace(/^\/\/[^\n]*\n/, '');
|
|
166
|
+
// Try each detector against each architecture file
|
|
167
|
+
const crudRule = detectGenericCRUD(filePath, content);
|
|
168
|
+
if (crudRule)
|
|
169
|
+
rules.push(crudRule);
|
|
170
|
+
const cmdRule = detectCommandRegistration(filePath, content);
|
|
171
|
+
if (cmdRule)
|
|
172
|
+
rules.push(cmdRule);
|
|
173
|
+
const typesRule = detectCentralTypes(filePath, content, sourceInventory);
|
|
174
|
+
if (typesRule)
|
|
175
|
+
rules.push(typesRule);
|
|
176
|
+
const idRule = detectIDGeneration(filePath, content);
|
|
177
|
+
if (idRule)
|
|
178
|
+
rules.push(idRule);
|
|
179
|
+
}
|
|
180
|
+
// Template detection uses inventory only (not a specific architecture file)
|
|
181
|
+
const templateRule = detectTemplateRendering(sourceInventory);
|
|
182
|
+
if (templateRule)
|
|
183
|
+
rules.push(templateRule);
|
|
184
|
+
return rules;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=pattern-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-rules.js","sourceRoot":"","sources":["../../../src/ai/codebase/pattern-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads project-specific rules from `.planr/rules.md`.
|
|
3
|
+
*
|
|
4
|
+
* These rules are injected directly into AI prompts so project
|
|
5
|
+
* owners can control how the AI generates tasks, names files,
|
|
6
|
+
* and follows architectural conventions — without modifying code.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Read `.planr/rules.md` from the project directory.
|
|
10
|
+
*
|
|
11
|
+
* @returns The trimmed rules content, or `null` if the file doesn't exist or is empty.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readProjectRules(projectDir: string): Promise<string | null>;
|
|
14
|
+
//# sourceMappingURL=rules-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-reader.d.ts","sourceRoot":"","sources":["../../../src/ai/codebase/rules-reader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMjF"}
|