aios-core 4.2.13 → 4.2.14
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/.aios-core/core/code-intel/helpers/dev-helper.js +206 -0
- package/.aios-core/core/registry/registry-schema.json +166 -166
- package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +3 -3
- package/.aios-core/data/entity-registry.yaml +27 -0
- package/.aios-core/development/scripts/approval-workflow.js +642 -642
- package/.aios-core/development/scripts/backup-manager.js +606 -606
- package/.aios-core/development/scripts/branch-manager.js +389 -389
- package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
- package/.aios-core/development/scripts/commit-message-generator.js +849 -849
- package/.aios-core/development/scripts/conflict-resolver.js +674 -674
- package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
- package/.aios-core/development/scripts/diff-generator.js +351 -351
- package/.aios-core/development/scripts/elicitation-engine.js +384 -384
- package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
- package/.aios-core/development/scripts/git-wrapper.js +461 -461
- package/.aios-core/development/scripts/manifest-preview.js +244 -244
- package/.aios-core/development/scripts/metrics-tracker.js +775 -775
- package/.aios-core/development/scripts/modification-validator.js +554 -554
- package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
- package/.aios-core/development/scripts/performance-analyzer.js +757 -757
- package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
- package/.aios-core/development/scripts/rollback-handler.js +530 -530
- package/.aios-core/development/scripts/security-checker.js +358 -358
- package/.aios-core/development/scripts/template-engine.js +239 -239
- package/.aios-core/development/scripts/template-validator.js +278 -278
- package/.aios-core/development/scripts/test-generator.js +843 -843
- package/.aios-core/development/scripts/transaction-manager.js +589 -589
- package/.aios-core/development/scripts/usage-tracker.js +673 -673
- package/.aios-core/development/scripts/validate-filenames.js +226 -226
- package/.aios-core/development/scripts/version-tracker.js +526 -526
- package/.aios-core/development/scripts/yaml-validator.js +396 -396
- package/.aios-core/development/tasks/build-autonomous.md +10 -4
- package/.aios-core/development/tasks/create-service.md +23 -0
- package/.aios-core/development/tasks/dev-develop-story.md +12 -6
- package/.aios-core/development/tasks/dev-suggest-refactoring.md +7 -1
- package/.aios-core/development/tasks/publish-npm.md +3 -3
- package/.aios-core/hooks/unified/README.md +1 -1
- package/.aios-core/install-manifest.yaml +65 -61
- package/.aios-core/manifests/schema/manifest-schema.json +190 -190
- package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
- package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
- package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
- package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
- package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
- package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
- package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
- package/.aios-core/product/templates/eslintrc-security.json +32 -32
- package/.aios-core/product/templates/github-actions-cd.yml +212 -212
- package/.aios-core/product/templates/github-actions-ci.yml +172 -172
- package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
- package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
- package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
- package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
- package/README.en.md +747 -0
- package/README.md +4 -2
- package/bin/aios.js +7 -4
- package/package.json +1 -1
- package/packages/aios-pro-cli/src/recover.js +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +6 -6
- package/packages/installer/src/wizard/pro-setup.js +3 -3
- package/scripts/package-synapse.js +5 -5
- package/scripts/validate-package-completeness.js +3 -3
- package/.aios-core/.session/current-session.json +0 -14
- package/.aios-core/data/registry-update-log.jsonl +0 -191
- package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +0 -335
- package/.aios-core/docs/component-creation-guide.md +0 -458
- package/.aios-core/docs/session-update-pattern.md +0 -307
- package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +0 -1963
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +0 -1190
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +0 -439
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +0 -5398
- package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +0 -523
- package/.aios-core/docs/template-syntax.md +0 -267
- package/.aios-core/docs/troubleshooting-guide.md +0 -625
- package/.aios-core/infrastructure/tests/utilities-audit-results.json +0 -501
- package/.aios-core/manifests/agents.csv +0 -29
- package/.aios-core/manifests/tasks.csv +0 -198
- package/.aios-core/manifests/workers.csv +0 -204
- package/.claude/rules/agent-authority.md +0 -105
- package/.claude/rules/coderabbit-integration.md +0 -93
- package/.claude/rules/ids-principles.md +0 -112
- package/.claude/rules/story-lifecycle.md +0 -139
- package/.claude/rules/workflow-execution.md +0 -150
- package/pro/README.md +0 -66
- package/pro/license/degradation.js +0 -220
- package/pro/license/errors.js +0 -450
- package/pro/license/feature-gate.js +0 -354
- package/pro/license/index.js +0 -181
- package/pro/license/license-api.js +0 -651
- package/pro/license/license-cache.js +0 -523
- package/pro/license/license-crypto.js +0 -303
- package/scripts/glue/README.md +0 -355
- package/scripts/glue/compose-agent-prompt.cjs +0 -362
- /package/.claude/hooks/{precompact-session-digest.js → precompact-session-digest.cjs} +0 -0
- /package/.claude/hooks/{synapse-engine.js → synapse-engine.cjs} +0 -0
|
@@ -1,279 +1,279 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template Validator for AIOS-FULLSTACK
|
|
3
|
-
* Validates component templates for required structure and placeholders
|
|
4
|
-
* @module template-validator
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs-extra');
|
|
8
|
-
const _path = require('path');
|
|
9
|
-
const _yaml = require('js-yaml');
|
|
10
|
-
const TemplateEngine = require('./template-engine');
|
|
11
|
-
|
|
12
|
-
class TemplateValidator {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.engine = new TemplateEngine();
|
|
15
|
-
this.requiredVariables = {
|
|
16
|
-
agent: [
|
|
17
|
-
'AGENT_NAME',
|
|
18
|
-
'AGENT_ID',
|
|
19
|
-
'AGENT_TITLE',
|
|
20
|
-
'AGENT_ICON',
|
|
21
|
-
'WHEN_TO_USE',
|
|
22
|
-
'PERSONA_ROLE',
|
|
23
|
-
'PERSONA_STYLE',
|
|
24
|
-
'PERSONA_IDENTITY',
|
|
25
|
-
'PERSONA_FOCUS'
|
|
26
|
-
],
|
|
27
|
-
task: [
|
|
28
|
-
'TASK_TITLE',
|
|
29
|
-
'TASK_ID',
|
|
30
|
-
'AGENT_NAME',
|
|
31
|
-
'VERSION',
|
|
32
|
-
'TASK_DESCRIPTION',
|
|
33
|
-
'OUTPUT_DESCRIPTION'
|
|
34
|
-
],
|
|
35
|
-
workflow: [
|
|
36
|
-
'WORKFLOW_ID',
|
|
37
|
-
'WORKFLOW_NAME',
|
|
38
|
-
'WORKFLOW_DESCRIPTION',
|
|
39
|
-
'WORKFLOW_VERSION',
|
|
40
|
-
'WORKFLOW_TYPE',
|
|
41
|
-
'AUTHOR',
|
|
42
|
-
'CREATED_DATE',
|
|
43
|
-
'LAST_MODIFIED'
|
|
44
|
-
]
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Validate a template file
|
|
50
|
-
* @param {string} templatePath - Path to template file
|
|
51
|
-
* @param {string} templateType - Type of template (agent, task, workflow)
|
|
52
|
-
* @returns {Promise<Object>} Validation result
|
|
53
|
-
*/
|
|
54
|
-
async validateTemplateFile(templatePath, templateType) {
|
|
55
|
-
try {
|
|
56
|
-
const template = await fs.readFile(templatePath, 'utf8');
|
|
57
|
-
return this.validateTemplate(template, templateType);
|
|
58
|
-
} catch (error) {
|
|
59
|
-
return {
|
|
60
|
-
valid: false,
|
|
61
|
-
errors: [`Failed to read template file: ${error.message}`]
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Validate a template string
|
|
68
|
-
* @param {string} template - Template content
|
|
69
|
-
* @param {string} templateType - Type of template
|
|
70
|
-
* @returns {Object} Validation result
|
|
71
|
-
*/
|
|
72
|
-
validateTemplate(template, templateType) {
|
|
73
|
-
const errors = [];
|
|
74
|
-
const warnings = [];
|
|
75
|
-
|
|
76
|
-
// Check template type is valid
|
|
77
|
-
if (!this.requiredVariables[templateType]) {
|
|
78
|
-
return {
|
|
79
|
-
valid: false,
|
|
80
|
-
errors: [`Unknown template type: ${templateType}`]
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Validate required variables
|
|
85
|
-
const requiredVars = this.requiredVariables[templateType];
|
|
86
|
-
const validation = this.engine.validateTemplate(template, requiredVars);
|
|
87
|
-
|
|
88
|
-
if (!validation.valid) {
|
|
89
|
-
errors.push(`Missing required variables: ${validation.missing.join(', ')}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Check for balanced conditionals
|
|
93
|
-
const conditionalCheck = this.checkBalancedConditionals(template);
|
|
94
|
-
if (!conditionalCheck.valid) {
|
|
95
|
-
errors.push(...conditionalCheck.errors);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Check for balanced loops
|
|
99
|
-
const loopCheck = this.checkBalancedLoops(template);
|
|
100
|
-
if (!loopCheck.valid) {
|
|
101
|
-
errors.push(...loopCheck.errors);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Template-specific validation
|
|
105
|
-
const specificCheck = this.validateSpecificTemplate(template, templateType);
|
|
106
|
-
if (!specificCheck.valid) {
|
|
107
|
-
errors.push(...specificCheck.errors);
|
|
108
|
-
}
|
|
109
|
-
warnings.push(...specificCheck.warnings);
|
|
110
|
-
|
|
111
|
-
// Check for potential security issues
|
|
112
|
-
const securityCheck = this.checkSecurityIssues(template);
|
|
113
|
-
if (!securityCheck.valid) {
|
|
114
|
-
errors.push(...securityCheck.errors);
|
|
115
|
-
}
|
|
116
|
-
warnings.push(...securityCheck.warnings);
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
valid: errors.length === 0,
|
|
120
|
-
errors,
|
|
121
|
-
warnings,
|
|
122
|
-
variables: this.engine.getTemplateVariables(template)
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Check for balanced conditional blocks
|
|
128
|
-
* @private
|
|
129
|
-
*/
|
|
130
|
-
checkBalancedConditionals(template) {
|
|
131
|
-
const errors = [];
|
|
132
|
-
const openTags = template.match(/\{\{#IF_([^}]+)\}\}/g) || [];
|
|
133
|
-
const closeTags = template.match(/\{\{\/IF_([^}]+)\}\}/g) || [];
|
|
134
|
-
|
|
135
|
-
const openConditions = openTags.map(tag => tag.match(/IF_([^}]+)/)[1]);
|
|
136
|
-
const closeConditions = closeTags.map(tag => tag.match(/IF_([^}]+)/)[1]);
|
|
137
|
-
|
|
138
|
-
// Check each open has a close
|
|
139
|
-
for (const condition of openConditions) {
|
|
140
|
-
if (!closeConditions.includes(condition)) {
|
|
141
|
-
errors.push(`Unclosed conditional: {{#IF_${condition}}}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Check each close has an open
|
|
146
|
-
for (const condition of closeConditions) {
|
|
147
|
-
if (!openConditions.includes(condition)) {
|
|
148
|
-
errors.push(`Unexpected closing tag: {{/IF_${condition}}}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return { valid: errors.length === 0, errors };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Check for balanced loop blocks
|
|
157
|
-
* @private
|
|
158
|
-
*/
|
|
159
|
-
checkBalancedLoops(template) {
|
|
160
|
-
const errors = [];
|
|
161
|
-
const openTags = template.match(/\{\{#EACH_([^}]+)\}\}/g) || [];
|
|
162
|
-
const closeTags = template.match(/\{\{\/EACH_([^}]+)\}\}/g) || [];
|
|
163
|
-
|
|
164
|
-
const openLoops = openTags.map(tag => tag.match(/EACH_([^}]+)/)[1]);
|
|
165
|
-
const closeLoops = closeTags.map(tag => tag.match(/EACH_([^}]+)/)[1]);
|
|
166
|
-
|
|
167
|
-
// Check each open has a close
|
|
168
|
-
for (const loop of openLoops) {
|
|
169
|
-
if (!closeLoops.includes(loop)) {
|
|
170
|
-
errors.push(`Unclosed loop: {{#EACH_${loop}}}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Check each close has an open
|
|
175
|
-
for (const loop of closeLoops) {
|
|
176
|
-
if (!openLoops.includes(loop)) {
|
|
177
|
-
errors.push(`Unexpected closing tag: {{/EACH_${loop}}}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return { valid: errors.length === 0, errors };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Template-specific validation
|
|
186
|
-
* @private
|
|
187
|
-
*/
|
|
188
|
-
validateSpecificTemplate(template, templateType) {
|
|
189
|
-
const errors = [];
|
|
190
|
-
const warnings = [];
|
|
191
|
-
|
|
192
|
-
switch (templateType) {
|
|
193
|
-
case 'agent':
|
|
194
|
-
// Check for YAML structure
|
|
195
|
-
if (!template.includes('agent:') || !template.includes('persona:')) {
|
|
196
|
-
errors.push('Agent template must include agent: and persona: sections');
|
|
197
|
-
}
|
|
198
|
-
if (!template.includes('commands:')) {
|
|
199
|
-
warnings.push('Agent template should include commands: section');
|
|
200
|
-
}
|
|
201
|
-
break;
|
|
202
|
-
|
|
203
|
-
case 'task':
|
|
204
|
-
// Check for markdown headers
|
|
205
|
-
if (!template.includes('# {{TASK_TITLE}}')) {
|
|
206
|
-
warnings.push('Task template should start with # {{TASK_TITLE}}');
|
|
207
|
-
}
|
|
208
|
-
if (!template.includes('## Workflow')) {
|
|
209
|
-
warnings.push('Task template should include ## Workflow section');
|
|
210
|
-
}
|
|
211
|
-
break;
|
|
212
|
-
|
|
213
|
-
case 'workflow':
|
|
214
|
-
// Check for YAML structure
|
|
215
|
-
if (!template.includes('workflow:') || !template.includes('steps:')) {
|
|
216
|
-
errors.push('Workflow template must include workflow: and steps: sections');
|
|
217
|
-
}
|
|
218
|
-
if (!template.includes('metadata:')) {
|
|
219
|
-
warnings.push('Workflow template should include metadata: section');
|
|
220
|
-
}
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return { valid: errors.length === 0, errors, warnings };
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Check for potential security issues in template
|
|
229
|
-
* @private
|
|
230
|
-
*/
|
|
231
|
-
checkSecurityIssues(template) {
|
|
232
|
-
const errors = [];
|
|
233
|
-
const warnings = [];
|
|
234
|
-
|
|
235
|
-
// Check for dangerous patterns
|
|
236
|
-
const dangerousPatterns = [
|
|
237
|
-
{ pattern: /eval\s*\(/, message: 'Template contains eval() - security risk' },
|
|
238
|
-
{ pattern: /Function\s*\(/, message: 'Template contains Function() - security risk' },
|
|
239
|
-
{ pattern: /require\s*\([^'"]+\)/, message: 'Dynamic require detected - potential security risk' },
|
|
240
|
-
{ pattern: /<script/i, message: 'Script tags detected in template' }
|
|
241
|
-
];
|
|
242
|
-
|
|
243
|
-
for (const { pattern, message } of dangerousPatterns) {
|
|
244
|
-
if (pattern.test(template)) {
|
|
245
|
-
errors.push(message);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Check for suspicious patterns
|
|
250
|
-
if (template.includes('__proto__') || template.includes('constructor')) {
|
|
251
|
-
warnings.push('Template contains potentially dangerous property access');
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return { valid: errors.length === 0, errors, warnings };
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Get required variables for a template type
|
|
259
|
-
* @param {string} templateType - Type of template
|
|
260
|
-
* @returns {string[]} Array of required variable names
|
|
261
|
-
*/
|
|
262
|
-
getRequiredVariables(templateType) {
|
|
263
|
-
return this.requiredVariables[templateType] || [];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Add custom required variables for a template type
|
|
268
|
-
* @param {string} templateType - Type of template
|
|
269
|
-
* @param {string[]} variables - Additional required variables
|
|
270
|
-
*/
|
|
271
|
-
addRequiredVariables(templateType, variables) {
|
|
272
|
-
if (!this.requiredVariables[templateType]) {
|
|
273
|
-
this.requiredVariables[templateType] = [];
|
|
274
|
-
}
|
|
275
|
-
this.requiredVariables[templateType].push(...variables);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Template Validator for AIOS-FULLSTACK
|
|
3
|
+
* Validates component templates for required structure and placeholders
|
|
4
|
+
* @module template-validator
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const _path = require('path');
|
|
9
|
+
const _yaml = require('js-yaml');
|
|
10
|
+
const TemplateEngine = require('./template-engine');
|
|
11
|
+
|
|
12
|
+
class TemplateValidator {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.engine = new TemplateEngine();
|
|
15
|
+
this.requiredVariables = {
|
|
16
|
+
agent: [
|
|
17
|
+
'AGENT_NAME',
|
|
18
|
+
'AGENT_ID',
|
|
19
|
+
'AGENT_TITLE',
|
|
20
|
+
'AGENT_ICON',
|
|
21
|
+
'WHEN_TO_USE',
|
|
22
|
+
'PERSONA_ROLE',
|
|
23
|
+
'PERSONA_STYLE',
|
|
24
|
+
'PERSONA_IDENTITY',
|
|
25
|
+
'PERSONA_FOCUS'
|
|
26
|
+
],
|
|
27
|
+
task: [
|
|
28
|
+
'TASK_TITLE',
|
|
29
|
+
'TASK_ID',
|
|
30
|
+
'AGENT_NAME',
|
|
31
|
+
'VERSION',
|
|
32
|
+
'TASK_DESCRIPTION',
|
|
33
|
+
'OUTPUT_DESCRIPTION'
|
|
34
|
+
],
|
|
35
|
+
workflow: [
|
|
36
|
+
'WORKFLOW_ID',
|
|
37
|
+
'WORKFLOW_NAME',
|
|
38
|
+
'WORKFLOW_DESCRIPTION',
|
|
39
|
+
'WORKFLOW_VERSION',
|
|
40
|
+
'WORKFLOW_TYPE',
|
|
41
|
+
'AUTHOR',
|
|
42
|
+
'CREATED_DATE',
|
|
43
|
+
'LAST_MODIFIED'
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validate a template file
|
|
50
|
+
* @param {string} templatePath - Path to template file
|
|
51
|
+
* @param {string} templateType - Type of template (agent, task, workflow)
|
|
52
|
+
* @returns {Promise<Object>} Validation result
|
|
53
|
+
*/
|
|
54
|
+
async validateTemplateFile(templatePath, templateType) {
|
|
55
|
+
try {
|
|
56
|
+
const template = await fs.readFile(templatePath, 'utf8');
|
|
57
|
+
return this.validateTemplate(template, templateType);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return {
|
|
60
|
+
valid: false,
|
|
61
|
+
errors: [`Failed to read template file: ${error.message}`]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Validate a template string
|
|
68
|
+
* @param {string} template - Template content
|
|
69
|
+
* @param {string} templateType - Type of template
|
|
70
|
+
* @returns {Object} Validation result
|
|
71
|
+
*/
|
|
72
|
+
validateTemplate(template, templateType) {
|
|
73
|
+
const errors = [];
|
|
74
|
+
const warnings = [];
|
|
75
|
+
|
|
76
|
+
// Check template type is valid
|
|
77
|
+
if (!this.requiredVariables[templateType]) {
|
|
78
|
+
return {
|
|
79
|
+
valid: false,
|
|
80
|
+
errors: [`Unknown template type: ${templateType}`]
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Validate required variables
|
|
85
|
+
const requiredVars = this.requiredVariables[templateType];
|
|
86
|
+
const validation = this.engine.validateTemplate(template, requiredVars);
|
|
87
|
+
|
|
88
|
+
if (!validation.valid) {
|
|
89
|
+
errors.push(`Missing required variables: ${validation.missing.join(', ')}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check for balanced conditionals
|
|
93
|
+
const conditionalCheck = this.checkBalancedConditionals(template);
|
|
94
|
+
if (!conditionalCheck.valid) {
|
|
95
|
+
errors.push(...conditionalCheck.errors);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check for balanced loops
|
|
99
|
+
const loopCheck = this.checkBalancedLoops(template);
|
|
100
|
+
if (!loopCheck.valid) {
|
|
101
|
+
errors.push(...loopCheck.errors);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Template-specific validation
|
|
105
|
+
const specificCheck = this.validateSpecificTemplate(template, templateType);
|
|
106
|
+
if (!specificCheck.valid) {
|
|
107
|
+
errors.push(...specificCheck.errors);
|
|
108
|
+
}
|
|
109
|
+
warnings.push(...specificCheck.warnings);
|
|
110
|
+
|
|
111
|
+
// Check for potential security issues
|
|
112
|
+
const securityCheck = this.checkSecurityIssues(template);
|
|
113
|
+
if (!securityCheck.valid) {
|
|
114
|
+
errors.push(...securityCheck.errors);
|
|
115
|
+
}
|
|
116
|
+
warnings.push(...securityCheck.warnings);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
valid: errors.length === 0,
|
|
120
|
+
errors,
|
|
121
|
+
warnings,
|
|
122
|
+
variables: this.engine.getTemplateVariables(template)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check for balanced conditional blocks
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
checkBalancedConditionals(template) {
|
|
131
|
+
const errors = [];
|
|
132
|
+
const openTags = template.match(/\{\{#IF_([^}]+)\}\}/g) || [];
|
|
133
|
+
const closeTags = template.match(/\{\{\/IF_([^}]+)\}\}/g) || [];
|
|
134
|
+
|
|
135
|
+
const openConditions = openTags.map(tag => tag.match(/IF_([^}]+)/)[1]);
|
|
136
|
+
const closeConditions = closeTags.map(tag => tag.match(/IF_([^}]+)/)[1]);
|
|
137
|
+
|
|
138
|
+
// Check each open has a close
|
|
139
|
+
for (const condition of openConditions) {
|
|
140
|
+
if (!closeConditions.includes(condition)) {
|
|
141
|
+
errors.push(`Unclosed conditional: {{#IF_${condition}}}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check each close has an open
|
|
146
|
+
for (const condition of closeConditions) {
|
|
147
|
+
if (!openConditions.includes(condition)) {
|
|
148
|
+
errors.push(`Unexpected closing tag: {{/IF_${condition}}}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { valid: errors.length === 0, errors };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check for balanced loop blocks
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
checkBalancedLoops(template) {
|
|
160
|
+
const errors = [];
|
|
161
|
+
const openTags = template.match(/\{\{#EACH_([^}]+)\}\}/g) || [];
|
|
162
|
+
const closeTags = template.match(/\{\{\/EACH_([^}]+)\}\}/g) || [];
|
|
163
|
+
|
|
164
|
+
const openLoops = openTags.map(tag => tag.match(/EACH_([^}]+)/)[1]);
|
|
165
|
+
const closeLoops = closeTags.map(tag => tag.match(/EACH_([^}]+)/)[1]);
|
|
166
|
+
|
|
167
|
+
// Check each open has a close
|
|
168
|
+
for (const loop of openLoops) {
|
|
169
|
+
if (!closeLoops.includes(loop)) {
|
|
170
|
+
errors.push(`Unclosed loop: {{#EACH_${loop}}}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check each close has an open
|
|
175
|
+
for (const loop of closeLoops) {
|
|
176
|
+
if (!openLoops.includes(loop)) {
|
|
177
|
+
errors.push(`Unexpected closing tag: {{/EACH_${loop}}}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { valid: errors.length === 0, errors };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Template-specific validation
|
|
186
|
+
* @private
|
|
187
|
+
*/
|
|
188
|
+
validateSpecificTemplate(template, templateType) {
|
|
189
|
+
const errors = [];
|
|
190
|
+
const warnings = [];
|
|
191
|
+
|
|
192
|
+
switch (templateType) {
|
|
193
|
+
case 'agent':
|
|
194
|
+
// Check for YAML structure
|
|
195
|
+
if (!template.includes('agent:') || !template.includes('persona:')) {
|
|
196
|
+
errors.push('Agent template must include agent: and persona: sections');
|
|
197
|
+
}
|
|
198
|
+
if (!template.includes('commands:')) {
|
|
199
|
+
warnings.push('Agent template should include commands: section');
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
case 'task':
|
|
204
|
+
// Check for markdown headers
|
|
205
|
+
if (!template.includes('# {{TASK_TITLE}}')) {
|
|
206
|
+
warnings.push('Task template should start with # {{TASK_TITLE}}');
|
|
207
|
+
}
|
|
208
|
+
if (!template.includes('## Workflow')) {
|
|
209
|
+
warnings.push('Task template should include ## Workflow section');
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
|
|
213
|
+
case 'workflow':
|
|
214
|
+
// Check for YAML structure
|
|
215
|
+
if (!template.includes('workflow:') || !template.includes('steps:')) {
|
|
216
|
+
errors.push('Workflow template must include workflow: and steps: sections');
|
|
217
|
+
}
|
|
218
|
+
if (!template.includes('metadata:')) {
|
|
219
|
+
warnings.push('Workflow template should include metadata: section');
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check for potential security issues in template
|
|
229
|
+
* @private
|
|
230
|
+
*/
|
|
231
|
+
checkSecurityIssues(template) {
|
|
232
|
+
const errors = [];
|
|
233
|
+
const warnings = [];
|
|
234
|
+
|
|
235
|
+
// Check for dangerous patterns
|
|
236
|
+
const dangerousPatterns = [
|
|
237
|
+
{ pattern: /eval\s*\(/, message: 'Template contains eval() - security risk' },
|
|
238
|
+
{ pattern: /Function\s*\(/, message: 'Template contains Function() - security risk' },
|
|
239
|
+
{ pattern: /require\s*\([^'"]+\)/, message: 'Dynamic require detected - potential security risk' },
|
|
240
|
+
{ pattern: /<script/i, message: 'Script tags detected in template' }
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
for (const { pattern, message } of dangerousPatterns) {
|
|
244
|
+
if (pattern.test(template)) {
|
|
245
|
+
errors.push(message);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Check for suspicious patterns
|
|
250
|
+
if (template.includes('__proto__') || template.includes('constructor')) {
|
|
251
|
+
warnings.push('Template contains potentially dangerous property access');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get required variables for a template type
|
|
259
|
+
* @param {string} templateType - Type of template
|
|
260
|
+
* @returns {string[]} Array of required variable names
|
|
261
|
+
*/
|
|
262
|
+
getRequiredVariables(templateType) {
|
|
263
|
+
return this.requiredVariables[templateType] || [];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Add custom required variables for a template type
|
|
268
|
+
* @param {string} templateType - Type of template
|
|
269
|
+
* @param {string[]} variables - Additional required variables
|
|
270
|
+
*/
|
|
271
|
+
addRequiredVariables(templateType, variables) {
|
|
272
|
+
if (!this.requiredVariables[templateType]) {
|
|
273
|
+
this.requiredVariables[templateType] = [];
|
|
274
|
+
}
|
|
275
|
+
this.requiredVariables[templateType].push(...variables);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
279
|
module.exports = TemplateValidator;
|