forge-dev-framework 1.0.1
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/rules/api-patterns.md +98 -0
- package/.claude/rules/security-baseline.md +204 -0
- package/.claude/rules/testing-standards.md +177 -0
- package/.claude/rules/ui-conventions.md +142 -0
- package/README.md +261 -0
- package/bin/forge.js +14 -0
- package/dist/bin/forge.js +14 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/base.d.ts +31 -0
- package/dist/commands/base.d.ts.map +1 -0
- package/dist/commands/base.js +31 -0
- package/dist/commands/base.js.map +1 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +175 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +159 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/help.d.ts +11 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +65 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +22 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +101 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stubs.d.ts +14 -0
- package/dist/commands/stubs.d.ts.map +1 -0
- package/dist/commands/stubs.js +30 -0
- package/dist/commands/stubs.js.map +1 -0
- package/dist/generators/index.d.ts +11 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +10 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/required-fields.d.ts +74 -0
- package/dist/generators/required-fields.d.ts.map +1 -0
- package/dist/generators/required-fields.js +179 -0
- package/dist/generators/required-fields.js.map +1 -0
- package/dist/generators/template-engine.d.ts +65 -0
- package/dist/generators/template-engine.d.ts.map +1 -0
- package/dist/generators/template-engine.js +209 -0
- package/dist/generators/template-engine.js.map +1 -0
- package/dist/generators/token-validator.d.ts +51 -0
- package/dist/generators/token-validator.d.ts.map +1 -0
- package/dist/generators/token-validator.js +141 -0
- package/dist/generators/token-validator.js.map +1 -0
- package/dist/generators/types.d.ts +433 -0
- package/dist/generators/types.d.ts.map +1 -0
- package/dist/generators/types.js +5 -0
- package/dist/generators/types.js.map +1 -0
- package/dist/generators/xml-task-generator.d.ts +67 -0
- package/dist/generators/xml-task-generator.d.ts.map +1 -0
- package/dist/generators/xml-task-generator.js +297 -0
- package/dist/generators/xml-task-generator.js.map +1 -0
- package/dist/git/__tests__/worktree.test.d.ts +5 -0
- package/dist/git/__tests__/worktree.test.d.ts.map +1 -0
- package/dist/git/__tests__/worktree.test.js +121 -0
- package/dist/git/__tests__/worktree.test.js.map +1 -0
- package/dist/git/codeowners.d.ts +101 -0
- package/dist/git/codeowners.d.ts.map +1 -0
- package/dist/git/codeowners.js +216 -0
- package/dist/git/codeowners.js.map +1 -0
- package/dist/git/commit.d.ts +135 -0
- package/dist/git/commit.d.ts.map +1 -0
- package/dist/git/commit.js +223 -0
- package/dist/git/commit.js.map +1 -0
- package/dist/git/hooks/commit-msg.d.ts +8 -0
- package/dist/git/hooks/commit-msg.d.ts.map +1 -0
- package/dist/git/hooks/commit-msg.js +34 -0
- package/dist/git/hooks/commit-msg.js.map +1 -0
- package/dist/git/hooks/pre-commit.d.ts +8 -0
- package/dist/git/hooks/pre-commit.d.ts.map +1 -0
- package/dist/git/hooks/pre-commit.js +34 -0
- package/dist/git/hooks/pre-commit.js.map +1 -0
- package/dist/git/pre-commit-hooks.d.ts +117 -0
- package/dist/git/pre-commit-hooks.d.ts.map +1 -0
- package/dist/git/pre-commit-hooks.js +270 -0
- package/dist/git/pre-commit-hooks.js.map +1 -0
- package/dist/git/wipe-protocol.d.ts +281 -0
- package/dist/git/wipe-protocol.d.ts.map +1 -0
- package/dist/git/wipe-protocol.js +237 -0
- package/dist/git/wipe-protocol.js.map +1 -0
- package/dist/git/worktree.d.ts +69 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +202 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/scripts/install.d.ts +8 -0
- package/dist/scripts/install.d.ts.map +1 -0
- package/dist/scripts/install.js +161 -0
- package/dist/scripts/install.js.map +1 -0
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +23 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/state.d.ts +56 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +6 -0
- package/dist/types/state.js.map +1 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +80 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +25 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +73 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/state-api.d.ts +128 -0
- package/dist/utils/state-api.d.ts.map +1 -0
- package/dist/utils/state-api.js +170 -0
- package/dist/utils/state-api.js.map +1 -0
- package/dist/utils/template-client.d.ts +73 -0
- package/dist/utils/template-client.d.ts.map +1 -0
- package/dist/utils/template-client.js +151 -0
- package/dist/utils/template-client.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Rendering Engine
|
|
3
|
+
*
|
|
4
|
+
* Uses Handlebars for template rendering with support for:
|
|
5
|
+
* - Variable interpolation ({{ variable }})
|
|
6
|
+
* - Conditional sections ({{#if}}...)
|
|
7
|
+
* - List iteration ({{#each}}...)
|
|
8
|
+
* - Custom helpers for formatting
|
|
9
|
+
*/
|
|
10
|
+
import Handlebars from 'handlebars';
|
|
11
|
+
import { readFile } from 'fs/promises';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { countTokens, validateTokenLimit } from './token-validator.js';
|
|
14
|
+
/**
|
|
15
|
+
* Template Engine class
|
|
16
|
+
*/
|
|
17
|
+
export class TemplateEngine {
|
|
18
|
+
config;
|
|
19
|
+
handlebars;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
this.handlebars = Handlebars.create();
|
|
23
|
+
this.registerHelpers();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Register custom Handlebars helpers
|
|
27
|
+
*/
|
|
28
|
+
registerHelpers() {
|
|
29
|
+
// Equals helper
|
|
30
|
+
this.handlebars.registerHelper('eq', function (a, b) {
|
|
31
|
+
return a === b;
|
|
32
|
+
});
|
|
33
|
+
// Not equals helper
|
|
34
|
+
this.handlebars.registerHelper('ne', function (a, b) {
|
|
35
|
+
return a !== b;
|
|
36
|
+
});
|
|
37
|
+
// And helper
|
|
38
|
+
this.handlebars.registerHelper('and', function (...args) {
|
|
39
|
+
// Last arg is options object
|
|
40
|
+
const options = args.pop();
|
|
41
|
+
return args.slice(0, -1).every((arg) => Boolean(arg));
|
|
42
|
+
});
|
|
43
|
+
// Or helper
|
|
44
|
+
this.handlebars.registerHelper('or', function (...args) {
|
|
45
|
+
// Last arg is options object
|
|
46
|
+
const options = args.pop();
|
|
47
|
+
return args.slice(0, -1).some((arg) => Boolean(arg));
|
|
48
|
+
});
|
|
49
|
+
// Default value helper
|
|
50
|
+
this.handlebars.registerHelper('default', function (value, defaultValue) {
|
|
51
|
+
return value ?? defaultValue;
|
|
52
|
+
});
|
|
53
|
+
// JSON stringify helper
|
|
54
|
+
this.handlebars.registerHelper('json', function (context, indent = 2) {
|
|
55
|
+
return JSON.stringify(context, null, indent);
|
|
56
|
+
});
|
|
57
|
+
// Concat helper
|
|
58
|
+
this.handlebars.registerHelper('concat', function (...args) {
|
|
59
|
+
// Last arg is options object
|
|
60
|
+
const options = args.pop();
|
|
61
|
+
return args.slice(0, -1).join('');
|
|
62
|
+
});
|
|
63
|
+
// ToLower helper
|
|
64
|
+
this.handlebars.registerHelper('toLowerCase', function (str) {
|
|
65
|
+
return str.toLowerCase();
|
|
66
|
+
});
|
|
67
|
+
// ToUpper helper
|
|
68
|
+
this.handlebars.registerHelper('toUpperCase', function (str) {
|
|
69
|
+
return str.toUpperCase();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Load a template file
|
|
74
|
+
*/
|
|
75
|
+
async loadTemplate(templateName) {
|
|
76
|
+
const templatePath = join(this.config.templatesDir, templateName);
|
|
77
|
+
return await readFile(templatePath, 'utf-8');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get token limit for a specific template
|
|
81
|
+
*/
|
|
82
|
+
getTokenLimit(templateName) {
|
|
83
|
+
const limits = {
|
|
84
|
+
'CLAUDE.md': this.config.tokenLimits.claude,
|
|
85
|
+
'REQUIREMENTS.md': this.config.tokenLimits.requirements,
|
|
86
|
+
'PLAN.md': this.config.tokenLimits.plan,
|
|
87
|
+
};
|
|
88
|
+
// Rules files
|
|
89
|
+
if (templateName.includes('rules/')) {
|
|
90
|
+
return this.config.tokenLimits.rules;
|
|
91
|
+
}
|
|
92
|
+
// Default limit for other templates
|
|
93
|
+
return limits[templateName] ?? 4000;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Render a template with the given context
|
|
97
|
+
*/
|
|
98
|
+
async render(templateName, context) {
|
|
99
|
+
try {
|
|
100
|
+
// Load template
|
|
101
|
+
const templateSource = await this.loadTemplate(templateName);
|
|
102
|
+
// Compile template
|
|
103
|
+
const template = this.handlebars.compile(templateSource);
|
|
104
|
+
// Render with context
|
|
105
|
+
const content = template(context);
|
|
106
|
+
// Count tokens
|
|
107
|
+
const tokenCount = countTokens(content);
|
|
108
|
+
// Get token limit for this template
|
|
109
|
+
const limit = this.getTokenLimit(templateName);
|
|
110
|
+
// Validate against limit
|
|
111
|
+
const { withinLimit, warnings } = validateTokenLimit(tokenCount, limit);
|
|
112
|
+
return {
|
|
113
|
+
content,
|
|
114
|
+
tokenCount,
|
|
115
|
+
withinLimit,
|
|
116
|
+
warnings,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
throw new Error(`Failed to render template ${templateName}: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Render a template string directly (without loading from file)
|
|
125
|
+
*/
|
|
126
|
+
renderString(templateString, context) {
|
|
127
|
+
try {
|
|
128
|
+
const template = this.handlebars.compile(templateString);
|
|
129
|
+
return template(context);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw new Error(`Failed to render template string: ${error.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Render multiple templates in batch
|
|
137
|
+
*/
|
|
138
|
+
async renderBatch(templates) {
|
|
139
|
+
const results = new Map();
|
|
140
|
+
for (const { name, context } of templates) {
|
|
141
|
+
const result = await this.render(name, context);
|
|
142
|
+
results.set(name, result);
|
|
143
|
+
}
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Validate context data structure
|
|
148
|
+
*/
|
|
149
|
+
validateContext(context) {
|
|
150
|
+
const errors = [];
|
|
151
|
+
// Required fields
|
|
152
|
+
if (!context.projectName) {
|
|
153
|
+
errors.push('Missing required field: projectName');
|
|
154
|
+
}
|
|
155
|
+
if (!context.version) {
|
|
156
|
+
errors.push('Missing required field: version');
|
|
157
|
+
}
|
|
158
|
+
if (!context.timestamp) {
|
|
159
|
+
errors.push('Missing required field: timestamp');
|
|
160
|
+
}
|
|
161
|
+
if (!context.techStack) {
|
|
162
|
+
errors.push('Missing required field: techStack');
|
|
163
|
+
}
|
|
164
|
+
if (!context.patterns) {
|
|
165
|
+
errors.push('Missing required field: patterns');
|
|
166
|
+
}
|
|
167
|
+
if (!context.rules) {
|
|
168
|
+
errors.push('Missing required field: rules');
|
|
169
|
+
}
|
|
170
|
+
if (!context.definitionOfDone) {
|
|
171
|
+
errors.push('Missing required field: definitionOfDone');
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
valid: errors.length === 0,
|
|
175
|
+
errors,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a partial template that can be included in other templates
|
|
180
|
+
*/
|
|
181
|
+
registerPartial(name, templateString) {
|
|
182
|
+
this.handlebars.registerPartial(name, templateString);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Register a partial from a file
|
|
186
|
+
*/
|
|
187
|
+
async registerPartialFromFile(name, partialPath) {
|
|
188
|
+
const templateSource = await readFile(join(this.config.templatesDir, partialPath), 'utf-8');
|
|
189
|
+
this.handlebars.registerPartial(name, templateSource);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create a template engine instance with default configuration
|
|
194
|
+
*/
|
|
195
|
+
export function createTemplateEngine(config) {
|
|
196
|
+
const defaultConfig = {
|
|
197
|
+
templatesDir: './src/templates',
|
|
198
|
+
outputDir: './',
|
|
199
|
+
tokenLimits: {
|
|
200
|
+
claude: 2000,
|
|
201
|
+
requirements: 4000,
|
|
202
|
+
plan: 6000,
|
|
203
|
+
rules: 1000,
|
|
204
|
+
},
|
|
205
|
+
...config,
|
|
206
|
+
};
|
|
207
|
+
return new TemplateEngine(defaultConfig);
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=template-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../../src/generators/template-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Counter and Validator
|
|
3
|
+
*
|
|
4
|
+
* Provides token counting functionality for templates with estimation
|
|
5
|
+
* and limit validation capabilities.
|
|
6
|
+
*/
|
|
7
|
+
import type { TokenCountResult } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Approximate token count for text
|
|
10
|
+
* Uses character-based estimation when tokenizer is not available
|
|
11
|
+
*
|
|
12
|
+
* Approximation: ~4 characters per token for English text
|
|
13
|
+
* This is a rough estimate - actual token count depends on the tokenizer used
|
|
14
|
+
*/
|
|
15
|
+
export declare function countTokens(text: string): number;
|
|
16
|
+
/**
|
|
17
|
+
* More accurate token count for code
|
|
18
|
+
* Code typically has more tokens per character due to punctuation
|
|
19
|
+
*/
|
|
20
|
+
export declare function countCodeTokens(code: string): number;
|
|
21
|
+
/**
|
|
22
|
+
* Count tokens in an array of strings
|
|
23
|
+
*/
|
|
24
|
+
export declare function countTokensArray(strings: string[]): number;
|
|
25
|
+
/**
|
|
26
|
+
* Validate token count against limit
|
|
27
|
+
*/
|
|
28
|
+
export declare function validateTokenLimit(tokenCount: number, limit: number, tolerance?: number): {
|
|
29
|
+
withinLimit: boolean;
|
|
30
|
+
warnings: string[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Detailed token count result with metadata
|
|
34
|
+
*/
|
|
35
|
+
export declare function getTokenCountDetails(text: string, isCode?: boolean): TokenCountResult;
|
|
36
|
+
/**
|
|
37
|
+
* Check if a file is within token limits
|
|
38
|
+
*/
|
|
39
|
+
export declare function checkFileTokenLimit(content: string, filePath: string, limits: Record<string, number>): {
|
|
40
|
+
withinLimit: boolean;
|
|
41
|
+
warnings: string[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Suggest content reduction strategies
|
|
45
|
+
*/
|
|
46
|
+
export declare function suggestReduction(tokenCount: number, limit: number): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Format token count for display
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatTokenCount(tokenCount: number): string;
|
|
51
|
+
//# sourceMappingURL=token-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-validator.d.ts","sourceRoot":"","sources":["../../src/generators/token-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYhD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAY,GACtB;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CA4B9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,OAAe,GAAG,gBAAgB,CAc5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAqB9C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK3D"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Counter and Validator
|
|
3
|
+
*
|
|
4
|
+
* Provides token counting functionality for templates with estimation
|
|
5
|
+
* and limit validation capabilities.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Approximate token count for text
|
|
9
|
+
* Uses character-based estimation when tokenizer is not available
|
|
10
|
+
*
|
|
11
|
+
* Approximation: ~4 characters per token for English text
|
|
12
|
+
* This is a rough estimate - actual token count depends on the tokenizer used
|
|
13
|
+
*/
|
|
14
|
+
export function countTokens(text) {
|
|
15
|
+
if (!text || text.length === 0) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
// Simple character-based approximation
|
|
19
|
+
// Average token is ~4 characters for English text
|
|
20
|
+
// This is conservative (may overestimate slightly)
|
|
21
|
+
const charCount = text.length;
|
|
22
|
+
const tokenCount = Math.ceil(charCount / 4);
|
|
23
|
+
return tokenCount;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* More accurate token count for code
|
|
27
|
+
* Code typically has more tokens per character due to punctuation
|
|
28
|
+
*/
|
|
29
|
+
export function countCodeTokens(code) {
|
|
30
|
+
if (!code || code.length === 0) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
// Code typically has ~3 characters per token
|
|
34
|
+
// Due to operators, punctuation, etc.
|
|
35
|
+
const charCount = code.length;
|
|
36
|
+
const tokenCount = Math.ceil(charCount / 3);
|
|
37
|
+
return tokenCount;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Count tokens in an array of strings
|
|
41
|
+
*/
|
|
42
|
+
export function countTokensArray(strings) {
|
|
43
|
+
return strings.reduce((total, str) => total + countTokens(str), 0);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validate token count against limit
|
|
47
|
+
*/
|
|
48
|
+
export function validateTokenLimit(tokenCount, limit, tolerance = 0.1 // 10% tolerance by default
|
|
49
|
+
) {
|
|
50
|
+
const warnings = [];
|
|
51
|
+
// Check if within limit with tolerance
|
|
52
|
+
const effectiveLimit = limit + Math.floor(limit * tolerance);
|
|
53
|
+
const withinLimit = tokenCount <= effectiveLimit;
|
|
54
|
+
// Generate warnings based on how close we are to limit
|
|
55
|
+
const percentage = (tokenCount / limit) * 100;
|
|
56
|
+
if (percentage > 100) {
|
|
57
|
+
warnings.push(`Token count (${tokenCount}) exceeds limit (${limit}) by ${Math.round(percentage - 100)}%`);
|
|
58
|
+
}
|
|
59
|
+
else if (percentage > 90) {
|
|
60
|
+
warnings.push(`Token count (${tokenCount}) is ${Math.round(percentage)}% of limit (${limit}) - consider reducing content`);
|
|
61
|
+
}
|
|
62
|
+
else if (percentage > 75) {
|
|
63
|
+
warnings.push(`Token count (${tokenCount}) is ${Math.round(percentage)}% of limit (${limit})`);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
withinLimit,
|
|
67
|
+
warnings,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Detailed token count result with metadata
|
|
72
|
+
*/
|
|
73
|
+
export function getTokenCountDetails(text, isCode = false) {
|
|
74
|
+
const warnings = [];
|
|
75
|
+
// Use appropriate counter
|
|
76
|
+
const count = isCode ? countCodeTokens(text) : countTokens(text);
|
|
77
|
+
// Add warning that this is an estimate
|
|
78
|
+
warnings.push('Token count is estimated using character-based approximation');
|
|
79
|
+
return {
|
|
80
|
+
count,
|
|
81
|
+
estimated: true,
|
|
82
|
+
warnings,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a file is within token limits
|
|
87
|
+
*/
|
|
88
|
+
export function checkFileTokenLimit(content, filePath, limits) {
|
|
89
|
+
// Determine if this is code
|
|
90
|
+
const isCode = /\.(ts|js|tsx|jsx|py|go|rs|java|cpp|c|h)$/.test(filePath);
|
|
91
|
+
const count = isCode ? countCodeTokens(content) : countTokens(content);
|
|
92
|
+
// Find matching limit
|
|
93
|
+
let limit = 4000; // default
|
|
94
|
+
const fileName = filePath.split('/').pop() || '';
|
|
95
|
+
if (fileName.includes('CLAUDE.md')) {
|
|
96
|
+
limit = limits.claude || 2000;
|
|
97
|
+
}
|
|
98
|
+
else if (fileName.includes('REQUIREMENTS.md')) {
|
|
99
|
+
limit = limits.requirements || 4000;
|
|
100
|
+
}
|
|
101
|
+
else if (fileName.includes('PLAN.md')) {
|
|
102
|
+
limit = limits.plan || 6000;
|
|
103
|
+
}
|
|
104
|
+
else if (filePath.includes('rules/')) {
|
|
105
|
+
limit = limits.rules || 1000;
|
|
106
|
+
}
|
|
107
|
+
return validateTokenLimit(count, limit);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Suggest content reduction strategies
|
|
111
|
+
*/
|
|
112
|
+
export function suggestReduction(tokenCount, limit) {
|
|
113
|
+
const suggestions = [];
|
|
114
|
+
const excess = tokenCount - limit;
|
|
115
|
+
if (excess <= 0) {
|
|
116
|
+
return suggestions;
|
|
117
|
+
}
|
|
118
|
+
const excessPercentage = Math.round((excess / limit) * 100);
|
|
119
|
+
// General suggestions
|
|
120
|
+
suggestions.push(`Reduce content by at least ${excess} tokens (${excessPercentage}% over limit)`);
|
|
121
|
+
suggestions.push('Move verbose sections to separate files and reference them');
|
|
122
|
+
suggestions.push('Use bullet points instead of full paragraphs');
|
|
123
|
+
suggestions.push('Remove redundant explanations');
|
|
124
|
+
suggestions.push('Consolidate similar items into lists');
|
|
125
|
+
// Specific suggestions based on file type
|
|
126
|
+
if (excessPercentage > 50) {
|
|
127
|
+
suggestions.push('Consider splitting this into multiple files');
|
|
128
|
+
suggestions.push('Extract detailed examples into a separate "examples" directory');
|
|
129
|
+
}
|
|
130
|
+
return suggestions;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Format token count for display
|
|
134
|
+
*/
|
|
135
|
+
export function formatTokenCount(tokenCount) {
|
|
136
|
+
if (tokenCount < 1000) {
|
|
137
|
+
return `${tokenCount} tokens`;
|
|
138
|
+
}
|
|
139
|
+
return `${(tokenCount / 1000).toFixed(1)}k tokens`;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=token-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-validator.js","sourceRoot":"","sources":["../../src/generators/token-validator.ts"],"names":[],"mappings":"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"}
|