ma-agents 3.2.0 → 3.4.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/.opencode/skills/.ma-agents.json +99 -99
- package/.roo/rules/00-ma-agents.md +13 -0
- package/.roo/skills/.ma-agents.json +241 -0
- package/.roo/skills/MANIFEST.yaml +254 -0
- package/.roo/skills/ai-audit-trail/SKILL.md +23 -0
- package/.roo/skills/auto-bug-detection/SKILL.md +169 -0
- package/.roo/skills/cmake-best-practices/SKILL.md +64 -0
- package/.roo/skills/cmake-best-practices/examples/cmake.md +59 -0
- package/.roo/skills/code-documentation/SKILL.md +57 -0
- package/.roo/skills/code-documentation/examples/cpp.md +29 -0
- package/.roo/skills/code-documentation/examples/csharp.md +28 -0
- package/.roo/skills/code-documentation/examples/javascript_typescript.md +28 -0
- package/.roo/skills/code-documentation/examples/python.md +57 -0
- package/.roo/skills/code-review/SKILL.md +43 -0
- package/.roo/skills/commit-message/SKILL.md +79 -0
- package/.roo/skills/cpp-best-practices/SKILL.md +234 -0
- package/.roo/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
- package/.roo/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
- package/.roo/skills/cpp-concurrency-safety/SKILL.md +60 -0
- package/.roo/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
- package/.roo/skills/cpp-const-correctness/SKILL.md +63 -0
- package/.roo/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
- package/.roo/skills/cpp-memory-handling/SKILL.md +42 -0
- package/.roo/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
- package/.roo/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
- package/.roo/skills/cpp-modern-composition/SKILL.md +64 -0
- package/.roo/skills/cpp-modern-composition/examples/composition.md +51 -0
- package/.roo/skills/cpp-robust-interfaces/SKILL.md +55 -0
- package/.roo/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
- package/.roo/skills/create-hardened-docker-skill/SKILL.md +637 -0
- package/.roo/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
- package/.roo/skills/csharp-best-practices/SKILL.md +278 -0
- package/.roo/skills/docker-hardening-verification/SKILL.md +28 -0
- package/.roo/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
- package/.roo/skills/docker-image-signing/SKILL.md +28 -0
- package/.roo/skills/docker-image-signing/scripts/sign-image.sh +33 -0
- package/.roo/skills/document-revision-history/SKILL.md +104 -0
- package/.roo/skills/git-workflow-skill/SKILL.md +194 -0
- package/.roo/skills/git-workflow-skill/hooks/commit-msg +61 -0
- package/.roo/skills/git-workflow-skill/hooks/pre-commit +38 -0
- package/.roo/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
- package/.roo/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
- package/.roo/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
- package/.roo/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
- package/.roo/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
- package/.roo/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
- package/.roo/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
- package/.roo/skills/js-ts-security-skill/SKILL.md +64 -0
- package/.roo/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
- package/.roo/skills/logging-best-practices/SKILL.md +50 -0
- package/.roo/skills/logging-best-practices/examples/cpp.md +36 -0
- package/.roo/skills/logging-best-practices/examples/csharp.md +49 -0
- package/.roo/skills/logging-best-practices/examples/javascript.md +77 -0
- package/.roo/skills/logging-best-practices/examples/python.md +57 -0
- package/.roo/skills/logging-best-practices/references/logging-standards.md +29 -0
- package/.roo/skills/open-presentation/SKILL.md +35 -0
- package/.roo/skills/opentelemetry-best-practices/SKILL.md +34 -0
- package/.roo/skills/opentelemetry-best-practices/examples/go.md +32 -0
- package/.roo/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
- package/.roo/skills/opentelemetry-best-practices/examples/python.md +37 -0
- package/.roo/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
- package/.roo/skills/python-best-practices/SKILL.md +385 -0
- package/.roo/skills/python-dependency-mgmt/SKILL.md +42 -0
- package/.roo/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
- package/.roo/skills/python-security-skill/SKILL.md +56 -0
- package/.roo/skills/python-security-skill/examples/security.md +56 -0
- package/.roo/skills/self-signed-cert/SKILL.md +42 -0
- package/.roo/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
- package/.roo/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
- package/.roo/skills/skill-creator/SKILL.md +196 -0
- package/.roo/skills/skill-creator/references/output-patterns.md +82 -0
- package/.roo/skills/skill-creator/references/workflows.md +28 -0
- package/.roo/skills/skill-creator/scripts/init_skill.py +208 -0
- package/.roo/skills/skill-creator/scripts/package_skill.py +99 -0
- package/.roo/skills/skill-creator/scripts/quick_validate.py +113 -0
- package/.roo/skills/story-status-lookup/SKILL.md +78 -0
- package/.roo/skills/test-accompanied-development/SKILL.md +50 -0
- package/.roo/skills/test-generator/SKILL.md +65 -0
- package/.roo/skills/vercel-react-best-practices/SKILL.md +109 -0
- package/.roo/skills/verify-hardened-docker-skill/SKILL.md +442 -0
- package/.roo/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
- package/README.md +21 -2
- package/bin/cli.js +55 -0
- package/lib/agents.js +46 -0
- package/lib/bmad-cache/cache-manifest.json +1 -1
- package/lib/bmad-customizations/bmm-demerzel.customize.yaml +36 -0
- package/lib/bmad-customizations/demerzel.md +32 -0
- package/lib/bmad-extension/module-help.csv +13 -0
- package/lib/bmad-extension/skills/bmad-ma-agent-ml/.gitkeep +0 -0
- package/lib/bmad-extension/skills/bmad-ma-agent-ml/SKILL.md +59 -0
- package/lib/bmad-extension/skills/bmad-ma-agent-ml/bmad-skill-manifest.yaml +11 -0
- package/lib/bmad-extension/skills/generate-backlog/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-advise/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-advise/SKILL.md +76 -0
- package/lib/bmad-extension/skills/ml-advise/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-advise/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-analysis/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-analysis/SKILL.md +60 -0
- package/lib/bmad-extension/skills/ml-analysis/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-analysis/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-architecture/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-architecture/SKILL.md +55 -0
- package/lib/bmad-extension/skills/ml-architecture/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-architecture/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-detailed-design/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-detailed-design/SKILL.md +67 -0
- package/lib/bmad-extension/skills/ml-detailed-design/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-detailed-design/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-eda/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-eda/SKILL.md +56 -0
- package/lib/bmad-extension/skills/ml-eda/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-eda/scripts/baseline_classifier.py +522 -0
- package/lib/bmad-extension/skills/ml-eda/scripts/class_weights_calculator.py +295 -0
- package/lib/bmad-extension/skills/ml-eda/scripts/clustering_explorer.py +383 -0
- package/lib/bmad-extension/skills/ml-eda/scripts/eda_analyzer.py +654 -0
- package/lib/bmad-extension/skills/ml-eda/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-experiment/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-experiment/SKILL.md +74 -0
- package/lib/bmad-extension/skills/ml-experiment/assets/advanced_trainer_configs.py +430 -0
- package/lib/bmad-extension/skills/ml-experiment/assets/quick_trainer_setup.py +233 -0
- package/lib/bmad-extension/skills/ml-experiment/assets/template_datamodule.py +219 -0
- package/lib/bmad-extension/skills/ml-experiment/assets/template_gnn_module.py +341 -0
- package/lib/bmad-extension/skills/ml-experiment/assets/template_lightning_module.py +158 -0
- package/lib/bmad-extension/skills/ml-experiment/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-experiment/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-hparam/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-hparam/SKILL.md +81 -0
- package/lib/bmad-extension/skills/ml-hparam/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-hparam/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-ideation/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-ideation/SKILL.md +50 -0
- package/lib/bmad-extension/skills/ml-ideation/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-ideation/scripts/validate_ml_prd.py +287 -0
- package/lib/bmad-extension/skills/ml-ideation/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-infra/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-infra/SKILL.md +58 -0
- package/lib/bmad-extension/skills/ml-infra/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-infra/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-retrospective/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-retrospective/SKILL.md +63 -0
- package/lib/bmad-extension/skills/ml-retrospective/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-retrospective/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-revision/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-revision/SKILL.md +82 -0
- package/lib/bmad-extension/skills/ml-revision/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-revision/skill.json +7 -0
- package/lib/bmad-extension/skills/ml-techspec/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-techspec/SKILL.md +80 -0
- package/lib/bmad-extension/skills/ml-techspec/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/ml-techspec/skill.json +7 -0
- package/lib/bmad.js +85 -8
- package/lib/skill-authoring.js +1 -1
- package/package.json +5 -4
- package/test/agent-injection-strategy.test.js +4 -4
- package/test/bmad-version-bump.test.js +34 -34
- package/test/build-bmad-args.test.js +13 -6
- package/test/convert-agents-to-skills.test.js +11 -1
- package/test/extension-module-restructure.test.js +31 -7
- package/test/migration-validation.test.js +14 -11
- package/test/roo-code-agent.test.js +166 -0
- package/test/roo-code-injection.test.js +172 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Tests for Story 18.1: Register Roo Code Agent in Registry
|
|
4
|
+
*
|
|
5
|
+
* Validates that the roo-code agent entry conforms to the required schema
|
|
6
|
+
* and resolves correctly through the existing config-driven registry pattern.
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const assert = require('assert');
|
|
11
|
+
|
|
12
|
+
let passed = 0;
|
|
13
|
+
let failed = 0;
|
|
14
|
+
const errors = [];
|
|
15
|
+
|
|
16
|
+
function test(name, fn) {
|
|
17
|
+
try {
|
|
18
|
+
fn();
|
|
19
|
+
console.log(` \u2713 ${name}`);
|
|
20
|
+
passed++;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error(` \u2717 ${name}: ${err.message}`);
|
|
23
|
+
failed++;
|
|
24
|
+
errors.push({ name, error: err.message });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { getAllAgents, getAgent, getAgentsByCategory } = require('../lib/agents');
|
|
29
|
+
const allAgents = getAllAgents();
|
|
30
|
+
const rooCode = getAgent('roo-code');
|
|
31
|
+
|
|
32
|
+
// --- Schema validation ---
|
|
33
|
+
|
|
34
|
+
console.log('\nRoo Code agent schema validation');
|
|
35
|
+
|
|
36
|
+
test('roo-code agent exists in registry', () => {
|
|
37
|
+
assert.ok(rooCode, 'roo-code agent should exist in the registry');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('id is "roo-code"', () => {
|
|
41
|
+
assert.strictEqual(rooCode.id, 'roo-code');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('name is "Roo Code"', () => {
|
|
45
|
+
assert.strictEqual(rooCode.name, 'Roo Code');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('category is "ide"', () => {
|
|
49
|
+
assert.strictEqual(rooCode.category, 'ide');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('getProjectPath is a function', () => {
|
|
53
|
+
assert.strictEqual(typeof rooCode.getProjectPath, 'function',
|
|
54
|
+
'getProjectPath should be a function');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('getGlobalPath is a function', () => {
|
|
58
|
+
assert.strictEqual(typeof rooCode.getGlobalPath, 'function',
|
|
59
|
+
'getGlobalPath should be a function');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('getProjectPath returns path ending in .roo/skills', () => {
|
|
63
|
+
const projectPath = rooCode.getProjectPath();
|
|
64
|
+
assert.ok(
|
|
65
|
+
projectPath.endsWith('.roo/skills') || projectPath.endsWith('.roo\\skills'),
|
|
66
|
+
`Expected path ending in .roo/skills, got: ${projectPath}`
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('getGlobalPath returns a non-empty string', () => {
|
|
71
|
+
const globalPath = rooCode.getGlobalPath();
|
|
72
|
+
assert.strictEqual(typeof globalPath, 'string');
|
|
73
|
+
assert.ok(globalPath.length > 0, 'getGlobalPath should return a non-empty string');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('getGlobalPath contains roo-cline (VS Code extension storage convention)', () => {
|
|
77
|
+
const globalPath = rooCode.getGlobalPath();
|
|
78
|
+
assert.ok(
|
|
79
|
+
globalPath.includes('roo-cline'),
|
|
80
|
+
`Expected global path to contain 'roo-cline', got: ${globalPath}`
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('fileExtension is ".md"', () => {
|
|
85
|
+
assert.strictEqual(rooCode.fileExtension, '.md');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('description is a non-empty string', () => {
|
|
89
|
+
assert.strictEqual(typeof rooCode.description, 'string',
|
|
90
|
+
'description should be a string');
|
|
91
|
+
assert.ok(rooCode.description.length > 0, 'description should not be empty');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('description mentions Cline fork lineage', () => {
|
|
95
|
+
assert.ok(rooCode.description.includes('Cline'),
|
|
96
|
+
`description should mention Cline fork lineage, got: ${rooCode.description}`);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('template is "generic"', () => {
|
|
100
|
+
assert.strictEqual(rooCode.template, 'generic');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('skillsDir is ".roo/skills"', () => {
|
|
104
|
+
assert.strictEqual(rooCode.skillsDir, '.roo/skills');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('instructionFiles is a non-empty array', () => {
|
|
108
|
+
assert.ok(Array.isArray(rooCode.instructionFiles),
|
|
109
|
+
'instructionFiles should be an array');
|
|
110
|
+
assert.ok(rooCode.instructionFiles.length > 0,
|
|
111
|
+
'instructionFiles should not be empty');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('instructionFiles targets .roo/rules/ directory', () => {
|
|
115
|
+
const hasRooRules = rooCode.instructionFiles.some(f =>
|
|
116
|
+
f.includes('.roo/rules/') || f.includes('.roo\\rules\\')
|
|
117
|
+
);
|
|
118
|
+
assert.ok(hasRooRules,
|
|
119
|
+
`instructionFiles should target .roo/rules/ directory, got: ${rooCode.instructionFiles}`);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('injectionStrategy is an object', () => {
|
|
123
|
+
assert.ok(rooCode.injectionStrategy && typeof rooCode.injectionStrategy === 'object',
|
|
124
|
+
'injectionStrategy should be an object');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('injectionStrategy.position is "top"', () => {
|
|
128
|
+
assert.strictEqual(rooCode.injectionStrategy.position, 'top');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// --- Registry resolution ---
|
|
132
|
+
|
|
133
|
+
console.log('\nRoo Code agent resolution');
|
|
134
|
+
|
|
135
|
+
test('getAgent("roo-code") returns the agent', () => {
|
|
136
|
+
const resolved = getAgent('roo-code');
|
|
137
|
+
assert.ok(resolved, 'getAgent("roo-code") should return an agent object');
|
|
138
|
+
assert.strictEqual(resolved.id, 'roo-code');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('roo-code appears in getAllAgents()', () => {
|
|
142
|
+
const ids = allAgents.map(a => a.id);
|
|
143
|
+
assert.ok(ids.includes('roo-code'), 'roo-code should appear in getAllAgents()');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('roo-code is in the ide category', () => {
|
|
147
|
+
const ideAgents = getAgentsByCategory('ide');
|
|
148
|
+
const ids = ideAgents.map(a => a.id);
|
|
149
|
+
assert.ok(ids.includes('roo-code'), 'roo-code should be in ide category');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('roo-code is distinct from cline', () => {
|
|
153
|
+
const cline = getAgent('cline');
|
|
154
|
+
assert.ok(cline, 'cline agent should still exist');
|
|
155
|
+
assert.notStrictEqual(cline.id, rooCode.id, 'roo-code and cline should be different agents');
|
|
156
|
+
assert.notStrictEqual(cline.skillsDir, rooCode.skillsDir,
|
|
157
|
+
'roo-code and cline should use different skills directories');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Print summary
|
|
161
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
162
|
+
if (errors.length > 0) {
|
|
163
|
+
console.log('\nFailed tests:');
|
|
164
|
+
errors.forEach(e => console.log(` - ${e.name}: ${e.error}`));
|
|
165
|
+
}
|
|
166
|
+
if (failed > 0) process.exit(1);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Tests for Story 18.3: Roo Code Rules Injection
|
|
4
|
+
*
|
|
5
|
+
* Validates that updateAgentInstructions() correctly creates/updates
|
|
6
|
+
* planning instructions in .roo/rules/00-ma-agents.md for Roo Code.
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const assert = require('assert');
|
|
11
|
+
const fs = require('fs-extra');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
|
|
15
|
+
let passed = 0;
|
|
16
|
+
let failed = 0;
|
|
17
|
+
const errors = [];
|
|
18
|
+
|
|
19
|
+
function test(name, fn) {
|
|
20
|
+
try {
|
|
21
|
+
fn();
|
|
22
|
+
console.log(` \u2713 ${name}`);
|
|
23
|
+
passed++;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error(` \u2717 ${name}: ${err.message}`);
|
|
26
|
+
failed++;
|
|
27
|
+
errors.push({ name, error: err.message });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function asyncTest(name, fn) {
|
|
32
|
+
try {
|
|
33
|
+
await fn();
|
|
34
|
+
console.log(` \u2713 ${name}`);
|
|
35
|
+
passed++;
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error(` \u2717 ${name}: ${err.message}`);
|
|
38
|
+
failed++;
|
|
39
|
+
errors.push({ name, error: err.message });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { _testUpdateAgentInstructions: updateAgentInstructions } = require('../lib/installer');
|
|
44
|
+
const { getAgent } = require('../lib/agents');
|
|
45
|
+
|
|
46
|
+
// --- Roo Code rules injection tests ---
|
|
47
|
+
|
|
48
|
+
console.log('\nRoo Code rules injection');
|
|
49
|
+
|
|
50
|
+
let tmpDir;
|
|
51
|
+
|
|
52
|
+
async function setup() {
|
|
53
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'roo-code-test-'));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function cleanup() {
|
|
57
|
+
if (tmpDir) {
|
|
58
|
+
await fs.remove(tmpDir);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
(async () => {
|
|
63
|
+
await setup();
|
|
64
|
+
|
|
65
|
+
const rooCode = getAgent('roo-code');
|
|
66
|
+
|
|
67
|
+
await asyncTest('creates .roo/rules/ directory and 00-ma-agents.md when absent', async () => {
|
|
68
|
+
const projectRoot = path.join(tmpDir, 'project-create');
|
|
69
|
+
await fs.ensureDir(projectRoot);
|
|
70
|
+
|
|
71
|
+
// Create a mock roo-code agent with paths relative to tmpDir
|
|
72
|
+
const agent = {
|
|
73
|
+
...rooCode,
|
|
74
|
+
getProjectPath: () => path.join(projectRoot, '.roo', 'skills'),
|
|
75
|
+
instructionFiles: ['.roo/rules/00-ma-agents.md'],
|
|
76
|
+
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
await updateAgentInstructions(agent, projectRoot);
|
|
80
|
+
|
|
81
|
+
const filePath = path.join(projectRoot, '.roo', 'rules', '00-ma-agents.md');
|
|
82
|
+
assert.ok(await fs.pathExists(filePath), '.roo/rules/00-ma-agents.md should be created');
|
|
83
|
+
|
|
84
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
85
|
+
assert.ok(content.includes('<!-- MA-AGENTS-START -->'), 'should contain start marker');
|
|
86
|
+
assert.ok(content.includes('<!-- MA-AGENTS-END -->'), 'should contain end marker');
|
|
87
|
+
assert.ok(content.includes('MANIFEST.yaml'), 'should reference MANIFEST.yaml');
|
|
88
|
+
assert.ok(content.includes('.roo/skills/MANIFEST.yaml'), 'should use .roo/skills/ path');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await asyncTest('updates existing content with markers in place (idempotent)', async () => {
|
|
92
|
+
const projectRoot = path.join(tmpDir, 'project-update');
|
|
93
|
+
await fs.ensureDir(projectRoot);
|
|
94
|
+
|
|
95
|
+
// Pre-create file with old markers
|
|
96
|
+
const rulesDir = path.join(projectRoot, '.roo', 'rules');
|
|
97
|
+
await fs.ensureDir(rulesDir);
|
|
98
|
+
const filePath = path.join(rulesDir, '00-ma-agents.md');
|
|
99
|
+
await fs.writeFile(filePath, '<!-- MA-AGENTS-START -->\nOLD CONTENT\n<!-- MA-AGENTS-END -->\n');
|
|
100
|
+
|
|
101
|
+
const agent = {
|
|
102
|
+
...rooCode,
|
|
103
|
+
getProjectPath: () => path.join(projectRoot, '.roo', 'skills'),
|
|
104
|
+
instructionFiles: ['.roo/rules/00-ma-agents.md'],
|
|
105
|
+
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
await updateAgentInstructions(agent, projectRoot);
|
|
109
|
+
|
|
110
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
111
|
+
assert.ok(!content.includes('OLD CONTENT'), 'old content should be replaced');
|
|
112
|
+
assert.ok(content.includes('MANIFEST.yaml'), 'should contain updated instruction');
|
|
113
|
+
// Verify only one set of markers
|
|
114
|
+
const startCount = (content.match(/<!-- MA-AGENTS-START -->/g) || []).length;
|
|
115
|
+
assert.strictEqual(startCount, 1, 'should have exactly one start marker');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await asyncTest('preserves user content when injecting into existing file', async () => {
|
|
119
|
+
const projectRoot = path.join(tmpDir, 'project-preserve');
|
|
120
|
+
await fs.ensureDir(projectRoot);
|
|
121
|
+
|
|
122
|
+
// Pre-create file with user content but no markers
|
|
123
|
+
const rulesDir = path.join(projectRoot, '.roo', 'rules');
|
|
124
|
+
await fs.ensureDir(rulesDir);
|
|
125
|
+
const filePath = path.join(rulesDir, '00-ma-agents.md');
|
|
126
|
+
await fs.writeFile(filePath, '# User Custom Rules\n\nAlways use TypeScript.\n');
|
|
127
|
+
|
|
128
|
+
const agent = {
|
|
129
|
+
...rooCode,
|
|
130
|
+
getProjectPath: () => path.join(projectRoot, '.roo', 'skills'),
|
|
131
|
+
instructionFiles: ['.roo/rules/00-ma-agents.md'],
|
|
132
|
+
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
await updateAgentInstructions(agent, projectRoot);
|
|
136
|
+
|
|
137
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
138
|
+
assert.ok(content.includes('<!-- MA-AGENTS-START -->'), 'should contain markers');
|
|
139
|
+
assert.ok(content.includes('Always use TypeScript'), 'should preserve user content');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await asyncTest('file can be cleanly removed (uninstall scenario)', async () => {
|
|
143
|
+
const projectRoot = path.join(tmpDir, 'project-uninstall');
|
|
144
|
+
await fs.ensureDir(projectRoot);
|
|
145
|
+
|
|
146
|
+
const agent = {
|
|
147
|
+
...rooCode,
|
|
148
|
+
getProjectPath: () => path.join(projectRoot, '.roo', 'skills'),
|
|
149
|
+
instructionFiles: ['.roo/rules/00-ma-agents.md'],
|
|
150
|
+
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Install first
|
|
154
|
+
await updateAgentInstructions(agent, projectRoot);
|
|
155
|
+
const filePath = path.join(projectRoot, '.roo', 'rules', '00-ma-agents.md');
|
|
156
|
+
assert.ok(await fs.pathExists(filePath), 'file should exist after install');
|
|
157
|
+
|
|
158
|
+
// Simulate uninstall by removing the file
|
|
159
|
+
await fs.remove(filePath);
|
|
160
|
+
assert.ok(!(await fs.pathExists(filePath)), 'file should be removed after uninstall');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await cleanup();
|
|
164
|
+
|
|
165
|
+
// Print summary
|
|
166
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
167
|
+
if (errors.length > 0) {
|
|
168
|
+
console.log('\nFailed tests:');
|
|
169
|
+
errors.forEach(e => console.log(` - ${e.name}: ${e.error}`));
|
|
170
|
+
}
|
|
171
|
+
if (failed > 0) process.exit(1);
|
|
172
|
+
})();
|