@fractary/faber 1.0.2 → 1.2.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 +12 -0
- package/dist/__tests__/config.test.d.ts +7 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +297 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/integration/forge-integration.test.d.ts +7 -0
- package/dist/__tests__/integration/forge-integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/forge-integration.test.js +370 -0
- package/dist/__tests__/integration/forge-integration.test.js.map +1 -0
- package/dist/__tests__/integration/init-workflow.test.d.ts +7 -0
- package/dist/__tests__/integration/init-workflow.test.d.ts.map +1 -0
- package/dist/__tests__/integration/init-workflow.test.js +309 -0
- package/dist/__tests__/integration/init-workflow.test.js.map +1 -0
- package/dist/config/__tests__/initializer.test.d.ts +7 -0
- package/dist/config/__tests__/initializer.test.d.ts.map +1 -0
- package/dist/config/__tests__/initializer.test.js +317 -0
- package/dist/config/__tests__/initializer.test.js.map +1 -0
- package/dist/config/initializer.d.ts +68 -0
- package/dist/config/initializer.d.ts.map +1 -0
- package/dist/config/initializer.js +230 -0
- package/dist/config/initializer.js.map +1 -0
- package/dist/config.d.ts +94 -46
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +100 -18
- package/dist/config.js.map +1 -1
- package/dist/spec/__tests__/manager.test.d.ts +7 -0
- package/dist/spec/__tests__/manager.test.d.ts.map +1 -0
- package/dist/spec/__tests__/manager.test.js +206 -0
- package/dist/spec/__tests__/manager.test.js.map +1 -0
- package/dist/spec/manager.d.ts +9 -1
- package/dist/spec/manager.d.ts.map +1 -1
- package/dist/spec/manager.js +23 -1
- package/dist/spec/manager.js.map +1 -1
- package/dist/types.d.ts +24 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow/__tests__/agent-executor.test.d.ts +5 -0
- package/dist/workflow/__tests__/agent-executor.test.d.ts.map +1 -0
- package/dist/workflow/__tests__/agent-executor.test.js +282 -0
- package/dist/workflow/__tests__/agent-executor.test.js.map +1 -0
- package/dist/workflow/agent-executor.d.ts +59 -0
- package/dist/workflow/agent-executor.d.ts.map +1 -0
- package/dist/workflow/agent-executor.js +150 -0
- package/dist/workflow/agent-executor.js.map +1 -0
- package/dist/workflow/faber.d.ts +13 -0
- package/dist/workflow/faber.d.ts.map +1 -1
- package/dist/workflow/faber.js +85 -0
- package/dist/workflow/faber.js.map +1 -1
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +3 -1
- package/dist/workflow/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fractary/faber - Init Workflow Integration Tests
|
|
4
|
+
*
|
|
5
|
+
* Integration tests for the full initialization workflow
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const initializer_1 = require("../../config/initializer");
|
|
44
|
+
const config_1 = require("../../config");
|
|
45
|
+
const manager_1 = require("../../spec/manager");
|
|
46
|
+
describe('Init Workflow Integration', () => {
|
|
47
|
+
const testDir = path.join(__dirname, '__test-init-workflow__');
|
|
48
|
+
const configPath = path.join(testDir, '.fractary', 'plugins', 'faber', 'config.yaml');
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
// Clean up test directory before each test
|
|
51
|
+
if (fs.existsSync(testDir)) {
|
|
52
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
55
|
+
// Mock process.cwd() to return testDir
|
|
56
|
+
jest.spyOn(process, 'cwd').mockReturnValue(testDir);
|
|
57
|
+
});
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
// Clean up test directory after each test
|
|
60
|
+
if (fs.existsSync(testDir)) {
|
|
61
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
// Restore mocks
|
|
64
|
+
jest.restoreAllMocks();
|
|
65
|
+
});
|
|
66
|
+
describe('CLI Init Command Simulation', () => {
|
|
67
|
+
it('should allow init without existing config', () => {
|
|
68
|
+
// Simulate CLI init command
|
|
69
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
70
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
71
|
+
// Verify config was created
|
|
72
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
73
|
+
// Verify config can be loaded
|
|
74
|
+
const loadedConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
75
|
+
expect(loadedConfig).not.toBeNull();
|
|
76
|
+
expect(loadedConfig?.schema_version).toBe('1.0');
|
|
77
|
+
});
|
|
78
|
+
it('should create YAML config that is human-readable', () => {
|
|
79
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
80
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
81
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
82
|
+
// Verify YAML format
|
|
83
|
+
expect(content).toContain('schema_version:');
|
|
84
|
+
expect(content).toContain('work:');
|
|
85
|
+
expect(content).toContain('platform: github');
|
|
86
|
+
expect(content).toContain('repo:');
|
|
87
|
+
expect(content).toContain('artifacts:');
|
|
88
|
+
expect(content).toContain('workflow:');
|
|
89
|
+
expect(content).toContain('autonomy: guarded');
|
|
90
|
+
// Should not contain JSON-specific syntax
|
|
91
|
+
expect(content).not.toContain('{');
|
|
92
|
+
expect(content).not.toContain('"schema_version"');
|
|
93
|
+
});
|
|
94
|
+
it('should create config with all required fields populated', () => {
|
|
95
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
96
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
97
|
+
const loadedConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
98
|
+
expect(loadedConfig).not.toBeNull();
|
|
99
|
+
expect(loadedConfig?.schema_version).toBe('1.0');
|
|
100
|
+
expect(loadedConfig?.work).toBeDefined();
|
|
101
|
+
expect(loadedConfig?.repo).toBeDefined();
|
|
102
|
+
expect(loadedConfig?.artifacts).toBeDefined();
|
|
103
|
+
expect(loadedConfig?.workflow).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
it('should allow customization during init', () => {
|
|
106
|
+
const createdPath = initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
107
|
+
repoOwner: 'my-org',
|
|
108
|
+
repoName: 'my-project',
|
|
109
|
+
workPlatform: 'jira',
|
|
110
|
+
repoPlatform: 'gitlab',
|
|
111
|
+
});
|
|
112
|
+
expect(fs.existsSync(createdPath)).toBe(true);
|
|
113
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
114
|
+
expect(config?.repo.owner).toBe('my-org');
|
|
115
|
+
expect(config?.repo.repo).toBe('my-project');
|
|
116
|
+
expect(config?.work.platform).toBe('jira');
|
|
117
|
+
expect(config?.repo.platform).toBe('gitlab');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('SpecManager Integration After Init', () => {
|
|
121
|
+
it('should allow SpecManager creation before init', () => {
|
|
122
|
+
// Before init - should work with defaults
|
|
123
|
+
const managerBefore = new manager_1.SpecManager();
|
|
124
|
+
expect(managerBefore).toBeDefined();
|
|
125
|
+
// After init - should use config
|
|
126
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
127
|
+
const managerAfter = new manager_1.SpecManager();
|
|
128
|
+
expect(managerAfter).toBeDefined();
|
|
129
|
+
});
|
|
130
|
+
it('should use config path after init', () => {
|
|
131
|
+
// Create manager before config exists
|
|
132
|
+
const manager1 = new manager_1.SpecManager();
|
|
133
|
+
expect(manager1).toBeDefined();
|
|
134
|
+
// Initialize with custom specs path
|
|
135
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
136
|
+
config.artifacts.specs.local_path = '/custom/specs';
|
|
137
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
138
|
+
// New manager should use config path
|
|
139
|
+
const manager2 = new manager_1.SpecManager();
|
|
140
|
+
expect(manager2).toBeDefined();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('Config Loading After Init', () => {
|
|
144
|
+
it('should load all config sections after init', () => {
|
|
145
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
146
|
+
const faberConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
147
|
+
const workConfig = (0, config_1.loadWorkConfig)(testDir);
|
|
148
|
+
const repoConfig = (0, config_1.loadRepoConfig)(testDir);
|
|
149
|
+
const specConfig = (0, config_1.loadSpecConfig)(testDir);
|
|
150
|
+
expect(faberConfig).not.toBeNull();
|
|
151
|
+
expect(workConfig).not.toBeNull();
|
|
152
|
+
expect(repoConfig).not.toBeNull();
|
|
153
|
+
expect(specConfig).toBeDefined();
|
|
154
|
+
});
|
|
155
|
+
it('should not throw after successful init', () => {
|
|
156
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
157
|
+
// All of these should work without throwing
|
|
158
|
+
expect(() => (0, config_1.loadFaberConfig)(testDir)).not.toThrow();
|
|
159
|
+
expect(() => (0, config_1.loadWorkConfig)(testDir)).not.toThrow();
|
|
160
|
+
expect(() => (0, config_1.loadRepoConfig)(testDir)).not.toThrow();
|
|
161
|
+
expect(() => (0, config_1.loadSpecConfig)(testDir)).not.toThrow();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe('Error Messages Without Init', () => {
|
|
165
|
+
it('should provide helpful error message when config missing', () => {
|
|
166
|
+
try {
|
|
167
|
+
(0, config_1.loadFaberConfig)(testDir);
|
|
168
|
+
fail('Should have thrown');
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
expect(error.message).toContain('fractary init');
|
|
172
|
+
expect(error.message).toContain('Expected config at:');
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
it('should guide user to run init command', () => {
|
|
176
|
+
try {
|
|
177
|
+
(0, config_1.loadWorkConfig)(testDir);
|
|
178
|
+
fail('Should have thrown');
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
expect(error.message).toContain('fractary init');
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
(0, config_1.loadRepoConfig)(testDir);
|
|
185
|
+
fail('Should have thrown');
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
expect(error.message).toContain('fractary init');
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
(0, config_1.loadSpecConfig)(testDir);
|
|
192
|
+
fail('Should have thrown');
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
expect(error.message).toContain('fractary init');
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe('Backward Compatibility', () => {
|
|
200
|
+
it('should work with existing JSON configs during migration', () => {
|
|
201
|
+
// Create legacy JSON config
|
|
202
|
+
const jsonConfigPath = configPath.replace(/\.yaml$/, '.json');
|
|
203
|
+
const dir = path.dirname(jsonConfigPath);
|
|
204
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
205
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
206
|
+
jsonConfig.repo.owner = 'legacy-owner';
|
|
207
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
208
|
+
// Should still be loadable
|
|
209
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
210
|
+
expect(config).not.toBeNull();
|
|
211
|
+
expect(config?.repo.owner).toBe('legacy-owner');
|
|
212
|
+
// SpecManager should work
|
|
213
|
+
const manager = new manager_1.SpecManager();
|
|
214
|
+
expect(manager).toBeDefined();
|
|
215
|
+
});
|
|
216
|
+
it('should migrate from JSON to YAML when re-initializing', () => {
|
|
217
|
+
// Create legacy JSON config
|
|
218
|
+
const jsonConfigPath = configPath.replace(/\.yaml$/, '.json');
|
|
219
|
+
const dir = path.dirname(jsonConfigPath);
|
|
220
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
221
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
222
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
223
|
+
// Re-initialize (creates YAML)
|
|
224
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
225
|
+
// Both should exist during migration
|
|
226
|
+
expect(fs.existsSync(jsonConfigPath)).toBe(true);
|
|
227
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
228
|
+
// YAML should be preferred
|
|
229
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
230
|
+
expect(config).not.toBeNull();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe('Real-World Scenarios', () => {
|
|
234
|
+
it('should support new project initialization flow', () => {
|
|
235
|
+
// 1. User runs: fractary init
|
|
236
|
+
const createdPath = initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
237
|
+
repoOwner: 'acme',
|
|
238
|
+
repoName: 'my-app',
|
|
239
|
+
});
|
|
240
|
+
expect(fs.existsSync(createdPath)).toBe(true);
|
|
241
|
+
// 2. User runs: fractary spec:create
|
|
242
|
+
const manager = new manager_1.SpecManager();
|
|
243
|
+
expect(manager).toBeDefined();
|
|
244
|
+
// 3. Config should be loaded correctly
|
|
245
|
+
const config = (0, config_1.loadFaberConfig)(testDir);
|
|
246
|
+
expect(config?.repo.owner).toBe('acme');
|
|
247
|
+
expect(config?.repo.repo).toBe('my-app');
|
|
248
|
+
});
|
|
249
|
+
it('should support existing project with partial config', () => {
|
|
250
|
+
// 1. Create work and repo configs separately (old setup)
|
|
251
|
+
const workConfigPath = path.join(testDir, '.fractary', 'plugins', 'work', 'config.json');
|
|
252
|
+
const repoConfigPath = path.join(testDir, '.fractary', 'plugins', 'repo', 'config.json');
|
|
253
|
+
fs.mkdirSync(path.dirname(workConfigPath), { recursive: true });
|
|
254
|
+
fs.mkdirSync(path.dirname(repoConfigPath), { recursive: true });
|
|
255
|
+
fs.writeFileSync(workConfigPath, JSON.stringify({ platform: 'github', owner: 'old', repo: 'old' }, null, 2), 'utf-8');
|
|
256
|
+
fs.writeFileSync(repoConfigPath, JSON.stringify({ platform: 'github', owner: 'old', repo: 'old' }, null, 2), 'utf-8');
|
|
257
|
+
// 2. Load config (should construct from individual configs)
|
|
258
|
+
const config = (0, config_1.loadFaberConfig)(testDir, { allowMissing: true });
|
|
259
|
+
expect(config).not.toBeNull();
|
|
260
|
+
expect(config?.work.platform).toBe('github');
|
|
261
|
+
expect(config?.repo.platform).toBe('github');
|
|
262
|
+
// 3. Upgrade to unified config
|
|
263
|
+
initializer_1.ConfigInitializer.initializeProject(testDir, {
|
|
264
|
+
repoOwner: 'new',
|
|
265
|
+
repoName: 'new',
|
|
266
|
+
});
|
|
267
|
+
// 4. New config should take precedence
|
|
268
|
+
const newConfig = (0, config_1.loadFaberConfig)(testDir);
|
|
269
|
+
expect(newConfig?.repo.owner).toBe('new');
|
|
270
|
+
});
|
|
271
|
+
it('should support CLI integration pattern', () => {
|
|
272
|
+
// Simulate CLI checking for config before running command
|
|
273
|
+
const configExists = initializer_1.ConfigInitializer.configExists(configPath);
|
|
274
|
+
expect(configExists).toBe(false);
|
|
275
|
+
// CLI detects no config and prompts user to init
|
|
276
|
+
if (!configExists) {
|
|
277
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
278
|
+
}
|
|
279
|
+
// Now config exists
|
|
280
|
+
expect(initializer_1.ConfigInitializer.configExists(configPath)).toBe(true);
|
|
281
|
+
// CLI can now run commands
|
|
282
|
+
const manager = new manager_1.SpecManager();
|
|
283
|
+
expect(manager).toBeDefined();
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
describe('Performance Requirements', () => {
|
|
287
|
+
it('should generate default config in under 100ms', () => {
|
|
288
|
+
const start = Date.now();
|
|
289
|
+
initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
290
|
+
const duration = Date.now() - start;
|
|
291
|
+
expect(duration).toBeLessThan(100);
|
|
292
|
+
});
|
|
293
|
+
it('should write config file quickly', () => {
|
|
294
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
295
|
+
const start = Date.now();
|
|
296
|
+
initializer_1.ConfigInitializer.writeConfig(config, configPath);
|
|
297
|
+
const duration = Date.now() - start;
|
|
298
|
+
expect(duration).toBeLessThan(100);
|
|
299
|
+
});
|
|
300
|
+
it('should handle concurrent SpecManager creation', () => {
|
|
301
|
+
initializer_1.ConfigInitializer.initializeProject(testDir);
|
|
302
|
+
// Create multiple managers concurrently (simulates parallel operations)
|
|
303
|
+
const managers = Array(10).fill(null).map(() => new manager_1.SpecManager());
|
|
304
|
+
expect(managers).toHaveLength(10);
|
|
305
|
+
managers.forEach(manager => expect(manager).toBeDefined());
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
//# sourceMappingURL=init-workflow.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-workflow.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/init-workflow.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializer.test.d.ts","sourceRoot":"","sources":["../../../src/config/__tests__/initializer.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fractary/faber - ConfigInitializer Tests
|
|
4
|
+
*
|
|
5
|
+
* Unit tests for the ConfigInitializer class
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const yaml = __importStar(require("js-yaml"));
|
|
44
|
+
const initializer_1 = require("../initializer");
|
|
45
|
+
describe('ConfigInitializer', () => {
|
|
46
|
+
const testDir = path.join(__dirname, '__test-configs__');
|
|
47
|
+
const yamlConfigPath = path.join(testDir, 'config.yaml');
|
|
48
|
+
const jsonConfigPath = path.join(testDir, 'config.json');
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
// Clean up test directory before each test
|
|
51
|
+
if (fs.existsSync(testDir)) {
|
|
52
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
55
|
+
});
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
// Clean up test directory after each test
|
|
58
|
+
if (fs.existsSync(testDir)) {
|
|
59
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
describe('generateDefaultConfig', () => {
|
|
63
|
+
it('should generate valid default config with all required sections', () => {
|
|
64
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
65
|
+
expect(config).toBeDefined();
|
|
66
|
+
expect(config.schema_version).toBe('1.0');
|
|
67
|
+
expect(config.work).toBeDefined();
|
|
68
|
+
expect(config.repo).toBeDefined();
|
|
69
|
+
expect(config.artifacts).toBeDefined();
|
|
70
|
+
expect(config.workflow).toBeDefined();
|
|
71
|
+
});
|
|
72
|
+
it('should set sensible defaults for work config', () => {
|
|
73
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
74
|
+
expect(config.work.platform).toBe('github');
|
|
75
|
+
});
|
|
76
|
+
it('should set sensible defaults for repo config', () => {
|
|
77
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
78
|
+
expect(config.repo.platform).toBe('github');
|
|
79
|
+
expect(config.repo.owner).toBe('');
|
|
80
|
+
expect(config.repo.repo).toBe('');
|
|
81
|
+
expect(config.repo.defaultBranch).toBe('main');
|
|
82
|
+
});
|
|
83
|
+
it('should set sensible defaults for artifacts config', () => {
|
|
84
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
85
|
+
expect(config.artifacts.specs).toEqual({
|
|
86
|
+
use_codex: false,
|
|
87
|
+
local_path: '/specs',
|
|
88
|
+
});
|
|
89
|
+
expect(config.artifacts.logs).toEqual({
|
|
90
|
+
use_codex: false,
|
|
91
|
+
local_path: '.fractary/logs',
|
|
92
|
+
});
|
|
93
|
+
expect(config.artifacts.state).toEqual({
|
|
94
|
+
use_codex: false,
|
|
95
|
+
local_path: '.fractary/plugins/faber',
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
it('should set sensible defaults for workflow config', () => {
|
|
99
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
100
|
+
expect(config.workflow.autonomy).toBe('guarded');
|
|
101
|
+
expect(config.workflow.phases).toBeDefined();
|
|
102
|
+
expect(config.workflow.phases.frame.enabled).toBe(true);
|
|
103
|
+
expect(config.workflow.phases.architect.enabled).toBe(true);
|
|
104
|
+
expect(config.workflow.phases.architect.refineSpec).toBe(true);
|
|
105
|
+
expect(config.workflow.phases.build.enabled).toBe(true);
|
|
106
|
+
expect(config.workflow.phases.evaluate.enabled).toBe(true);
|
|
107
|
+
expect(config.workflow.phases.evaluate.maxRetries).toBe(3);
|
|
108
|
+
expect(config.workflow.phases.release.enabled).toBe(true);
|
|
109
|
+
expect(config.workflow.phases.release.requestReviews).toBe(false);
|
|
110
|
+
expect(config.workflow.phases.release.reviewers).toEqual([]);
|
|
111
|
+
});
|
|
112
|
+
it('should generate config that matches FaberConfig type', () => {
|
|
113
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
114
|
+
// Type assertion - if this compiles, the type is correct
|
|
115
|
+
const typedConfig = config;
|
|
116
|
+
expect(typedConfig).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('writeConfig', () => {
|
|
120
|
+
it('should write config file in YAML format', () => {
|
|
121
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
122
|
+
initializer_1.ConfigInitializer.writeConfig(config, yamlConfigPath);
|
|
123
|
+
expect(fs.existsSync(yamlConfigPath)).toBe(true);
|
|
124
|
+
const content = fs.readFileSync(yamlConfigPath, 'utf-8');
|
|
125
|
+
expect(content).toContain('schema_version:'); // YAML format
|
|
126
|
+
expect(content).toContain('work:');
|
|
127
|
+
expect(content).toContain('repo:');
|
|
128
|
+
expect(content).toContain('artifacts:');
|
|
129
|
+
expect(content).toContain('workflow:');
|
|
130
|
+
});
|
|
131
|
+
it('should create parent directories if they do not exist', () => {
|
|
132
|
+
const nestedPath = path.join(testDir, 'nested', 'deep', 'config.yaml');
|
|
133
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
134
|
+
initializer_1.ConfigInitializer.writeConfig(config, nestedPath);
|
|
135
|
+
expect(fs.existsSync(nestedPath)).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
it('should write valid YAML that can be parsed back', () => {
|
|
138
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
139
|
+
initializer_1.ConfigInitializer.writeConfig(config, yamlConfigPath);
|
|
140
|
+
const content = fs.readFileSync(yamlConfigPath, 'utf-8');
|
|
141
|
+
const parsedConfig = yaml.load(content);
|
|
142
|
+
expect(parsedConfig).toEqual(config);
|
|
143
|
+
});
|
|
144
|
+
it('should overwrite existing config file', () => {
|
|
145
|
+
const config1 = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
146
|
+
config1.repo.owner = 'owner1';
|
|
147
|
+
initializer_1.ConfigInitializer.writeConfig(config1, yamlConfigPath);
|
|
148
|
+
const config2 = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
149
|
+
config2.repo.owner = 'owner2';
|
|
150
|
+
initializer_1.ConfigInitializer.writeConfig(config2, yamlConfigPath);
|
|
151
|
+
const content = fs.readFileSync(yamlConfigPath, 'utf-8');
|
|
152
|
+
const parsedConfig = yaml.load(content);
|
|
153
|
+
expect(parsedConfig.repo.owner).toBe('owner2');
|
|
154
|
+
});
|
|
155
|
+
it('should use default path when no path is provided', () => {
|
|
156
|
+
// Mock process.cwd() to return testDir
|
|
157
|
+
const originalCwd = process.cwd;
|
|
158
|
+
process.cwd = jest.fn(() => testDir);
|
|
159
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
160
|
+
initializer_1.ConfigInitializer.writeConfig(config);
|
|
161
|
+
const expectedPath = path.join(testDir, '.fractary', 'plugins', 'faber', 'config.yaml');
|
|
162
|
+
expect(fs.existsSync(expectedPath)).toBe(true);
|
|
163
|
+
// Restore original cwd
|
|
164
|
+
process.cwd = originalCwd;
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe('configExists', () => {
|
|
168
|
+
it('should return true when YAML config exists', () => {
|
|
169
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
170
|
+
initializer_1.ConfigInitializer.writeConfig(config, yamlConfigPath);
|
|
171
|
+
expect(initializer_1.ConfigInitializer.configExists(yamlConfigPath)).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
it('should return true when JSON config exists (legacy)', () => {
|
|
174
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
175
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
176
|
+
expect(initializer_1.ConfigInitializer.configExists(yamlConfigPath)).toBe(true); // Checks both .yaml and .json
|
|
177
|
+
});
|
|
178
|
+
it('should return false when config does not exist', () => {
|
|
179
|
+
expect(initializer_1.ConfigInitializer.configExists(yamlConfigPath)).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
it('should check default path when no path is provided', () => {
|
|
182
|
+
// Mock process.cwd() to return testDir
|
|
183
|
+
const originalCwd = process.cwd;
|
|
184
|
+
process.cwd = jest.fn(() => testDir);
|
|
185
|
+
expect(initializer_1.ConfigInitializer.configExists()).toBe(false);
|
|
186
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
187
|
+
initializer_1.ConfigInitializer.writeConfig(config);
|
|
188
|
+
expect(initializer_1.ConfigInitializer.configExists()).toBe(true);
|
|
189
|
+
// Restore original cwd
|
|
190
|
+
process.cwd = originalCwd;
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe('readConfig', () => {
|
|
194
|
+
it('should read YAML config correctly', () => {
|
|
195
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
196
|
+
config.repo.owner = 'test-owner';
|
|
197
|
+
initializer_1.ConfigInitializer.writeConfig(config, yamlConfigPath);
|
|
198
|
+
const readConfig = initializer_1.ConfigInitializer.readConfig(yamlConfigPath);
|
|
199
|
+
expect(readConfig).toEqual(config);
|
|
200
|
+
});
|
|
201
|
+
it('should read JSON config correctly (legacy)', () => {
|
|
202
|
+
const config = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
203
|
+
config.repo.owner = 'test-owner';
|
|
204
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
205
|
+
const readConfig = initializer_1.ConfigInitializer.readConfig(yamlConfigPath); // Checks .yaml first, then .json
|
|
206
|
+
expect(readConfig).toEqual(config);
|
|
207
|
+
});
|
|
208
|
+
it('should return null when config does not exist', () => {
|
|
209
|
+
const readConfig = initializer_1.ConfigInitializer.readConfig(yamlConfigPath);
|
|
210
|
+
expect(readConfig).toBeNull();
|
|
211
|
+
});
|
|
212
|
+
it('should prefer YAML over JSON when both exist', () => {
|
|
213
|
+
const yamlConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
214
|
+
yamlConfig.repo.owner = 'yaml-owner';
|
|
215
|
+
initializer_1.ConfigInitializer.writeConfig(yamlConfig, yamlConfigPath);
|
|
216
|
+
const jsonConfig = initializer_1.ConfigInitializer.generateDefaultConfig();
|
|
217
|
+
jsonConfig.repo.owner = 'json-owner';
|
|
218
|
+
fs.writeFileSync(jsonConfigPath, JSON.stringify(jsonConfig, null, 2), 'utf-8');
|
|
219
|
+
const readConfig = initializer_1.ConfigInitializer.readConfig(yamlConfigPath);
|
|
220
|
+
expect(readConfig?.repo.owner).toBe('yaml-owner');
|
|
221
|
+
});
|
|
222
|
+
it('should throw error when YAML is malformed', () => {
|
|
223
|
+
fs.writeFileSync(yamlConfigPath, 'invalid: yaml: content: [', 'utf-8');
|
|
224
|
+
expect(() => initializer_1.ConfigInitializer.readConfig(yamlConfigPath)).toThrow(/Failed to parse YAML/);
|
|
225
|
+
});
|
|
226
|
+
it('should throw error when JSON is malformed', () => {
|
|
227
|
+
fs.writeFileSync(jsonConfigPath, '{ invalid json }', 'utf-8');
|
|
228
|
+
expect(() => initializer_1.ConfigInitializer.readConfig(yamlConfigPath)).toThrow(/Failed to parse JSON/);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
describe('initializeProject', () => {
|
|
232
|
+
it('should create config file and return path', () => {
|
|
233
|
+
// Mock process.cwd() to return testDir
|
|
234
|
+
const originalCwd = process.cwd;
|
|
235
|
+
process.cwd = jest.fn(() => testDir);
|
|
236
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject();
|
|
237
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
238
|
+
expect(configPath).toBe(path.join(testDir, '.fractary', 'plugins', 'faber', 'config.yaml'));
|
|
239
|
+
// Restore original cwd
|
|
240
|
+
process.cwd = originalCwd;
|
|
241
|
+
});
|
|
242
|
+
it('should apply repoOwner override', () => {
|
|
243
|
+
// Mock process.cwd() to return testDir
|
|
244
|
+
const originalCwd = process.cwd;
|
|
245
|
+
process.cwd = jest.fn(() => testDir);
|
|
246
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(undefined, {
|
|
247
|
+
repoOwner: 'custom-owner',
|
|
248
|
+
});
|
|
249
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
250
|
+
expect(config?.repo.owner).toBe('custom-owner');
|
|
251
|
+
// Restore original cwd
|
|
252
|
+
process.cwd = originalCwd;
|
|
253
|
+
});
|
|
254
|
+
it('should apply repoName override', () => {
|
|
255
|
+
// Mock process.cwd() to return testDir
|
|
256
|
+
const originalCwd = process.cwd;
|
|
257
|
+
process.cwd = jest.fn(() => testDir);
|
|
258
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(undefined, {
|
|
259
|
+
repoName: 'custom-repo',
|
|
260
|
+
});
|
|
261
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
262
|
+
expect(config?.repo.repo).toBe('custom-repo');
|
|
263
|
+
// Restore original cwd
|
|
264
|
+
process.cwd = originalCwd;
|
|
265
|
+
});
|
|
266
|
+
it('should apply workPlatform override', () => {
|
|
267
|
+
// Mock process.cwd() to return testDir
|
|
268
|
+
const originalCwd = process.cwd;
|
|
269
|
+
process.cwd = jest.fn(() => testDir);
|
|
270
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(undefined, {
|
|
271
|
+
workPlatform: 'jira',
|
|
272
|
+
});
|
|
273
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
274
|
+
expect(config?.work.platform).toBe('jira');
|
|
275
|
+
// Restore original cwd
|
|
276
|
+
process.cwd = originalCwd;
|
|
277
|
+
});
|
|
278
|
+
it('should apply repoPlatform override', () => {
|
|
279
|
+
// Mock process.cwd() to return testDir
|
|
280
|
+
const originalCwd = process.cwd;
|
|
281
|
+
process.cwd = jest.fn(() => testDir);
|
|
282
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(undefined, {
|
|
283
|
+
repoPlatform: 'gitlab',
|
|
284
|
+
});
|
|
285
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
286
|
+
expect(config?.repo.platform).toBe('gitlab');
|
|
287
|
+
// Restore original cwd
|
|
288
|
+
process.cwd = originalCwd;
|
|
289
|
+
});
|
|
290
|
+
it('should apply multiple overrides simultaneously', () => {
|
|
291
|
+
// Mock process.cwd() to return testDir
|
|
292
|
+
const originalCwd = process.cwd;
|
|
293
|
+
process.cwd = jest.fn(() => testDir);
|
|
294
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(undefined, {
|
|
295
|
+
repoOwner: 'test-org',
|
|
296
|
+
repoName: 'test-repo',
|
|
297
|
+
workPlatform: 'linear',
|
|
298
|
+
repoPlatform: 'bitbucket',
|
|
299
|
+
});
|
|
300
|
+
const config = initializer_1.ConfigInitializer.readConfig(configPath);
|
|
301
|
+
expect(config?.repo.owner).toBe('test-org');
|
|
302
|
+
expect(config?.repo.repo).toBe('test-repo');
|
|
303
|
+
expect(config?.work.platform).toBe('linear');
|
|
304
|
+
expect(config?.repo.platform).toBe('bitbucket');
|
|
305
|
+
// Restore original cwd
|
|
306
|
+
process.cwd = originalCwd;
|
|
307
|
+
});
|
|
308
|
+
it('should use custom projectRoot when provided', () => {
|
|
309
|
+
const customRoot = path.join(testDir, 'custom-project');
|
|
310
|
+
fs.mkdirSync(customRoot, { recursive: true });
|
|
311
|
+
const configPath = initializer_1.ConfigInitializer.initializeProject(customRoot);
|
|
312
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
313
|
+
expect(configPath).toBe(path.join(customRoot, '.fractary', 'plugins', 'faber', 'config.yaml'));
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
//# sourceMappingURL=initializer.test.js.map
|