edsger 0.45.0 → 0.45.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/package.json +3 -3
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +3 -9
- package/dist/api/__tests__/app-store.test.d.ts +0 -7
- package/dist/api/__tests__/app-store.test.js +0 -60
- package/dist/api/__tests__/intelligence.test.d.ts +0 -11
- package/dist/api/__tests__/intelligence.test.js +0 -315
- package/dist/api/features/__tests__/feature-utils.test.d.ts +0 -4
- package/dist/api/features/__tests__/feature-utils.test.js +0 -370
- package/dist/api/features/__tests__/status-updater.test.d.ts +0 -4
- package/dist/api/features/__tests__/status-updater.test.js +0 -88
- package/dist/commands/build/__tests__/build.test.d.ts +0 -5
- package/dist/commands/build/__tests__/build.test.js +0 -206
- package/dist/commands/build/__tests__/detect-project.test.d.ts +0 -6
- package/dist/commands/build/__tests__/detect-project.test.js +0 -160
- package/dist/commands/build/__tests__/run-build.test.d.ts +0 -6
- package/dist/commands/build/__tests__/run-build.test.js +0 -433
- package/dist/commands/intelligence/__tests__/command.test.d.ts +0 -4
- package/dist/commands/intelligence/__tests__/command.test.js +0 -48
- package/dist/commands/workflow/core/__tests__/feature-filter.test.d.ts +0 -5
- package/dist/commands/workflow/core/__tests__/feature-filter.test.js +0 -316
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.d.ts +0 -4
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.js +0 -397
- package/dist/commands/workflow/core/__tests__/state-manager.test.d.ts +0 -4
- package/dist/commands/workflow/core/__tests__/state-manager.test.js +0 -384
- package/dist/config/__tests__/config.test.d.ts +0 -4
- package/dist/config/__tests__/config.test.js +0 -286
- package/dist/config/__tests__/feature-status.test.d.ts +0 -4
- package/dist/config/__tests__/feature-status.test.js +0 -111
- package/dist/errors/__tests__/index.test.d.ts +0 -4
- package/dist/errors/__tests__/index.test.js +0 -349
- package/dist/phases/app-store-generation/__tests__/agent.test.d.ts +0 -5
- package/dist/phases/app-store-generation/__tests__/agent.test.js +0 -142
- package/dist/phases/app-store-generation/__tests__/context.test.d.ts +0 -4
- package/dist/phases/app-store-generation/__tests__/context.test.js +0 -284
- package/dist/phases/app-store-generation/__tests__/prompts.test.d.ts +0 -4
- package/dist/phases/app-store-generation/__tests__/prompts.test.js +0 -122
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.d.ts +0 -5
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.js +0 -826
- package/dist/phases/code-review/__tests__/diff-utils.test.d.ts +0 -1
- package/dist/phases/code-review/__tests__/diff-utils.test.js +0 -101
- package/dist/phases/intelligence-analysis/__tests__/context.test.d.ts +0 -4
- package/dist/phases/intelligence-analysis/__tests__/context.test.js +0 -192
- package/dist/phases/intelligence-analysis/__tests__/matching.test.d.ts +0 -13
- package/dist/phases/intelligence-analysis/__tests__/matching.test.js +0 -154
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.d.ts +0 -5
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.js +0 -378
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.d.ts +0 -4
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.js +0 -33
- package/dist/phases/pr-execution/__tests__/file-assigner.test.d.ts +0 -1
- package/dist/phases/pr-execution/__tests__/file-assigner.test.js +0 -303
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.js +0 -157
- package/dist/phases/pr-resolve/__tests__/prompts.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/prompts.test.js +0 -116
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.js +0 -138
- package/dist/phases/pr-resolve/__tests__/types.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/types.test.js +0 -43
- package/dist/phases/pr-resolve/__tests__/workspace.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/workspace.test.js +0 -111
- package/dist/phases/pr-review/__tests__/prompts.test.d.ts +0 -1
- package/dist/phases/pr-review/__tests__/prompts.test.js +0 -49
- package/dist/phases/pr-review/__tests__/review-comments.test.d.ts +0 -1
- package/dist/phases/pr-review/__tests__/review-comments.test.js +0 -110
- package/dist/phases/pr-shared/__tests__/agent-utils.test.d.ts +0 -1
- package/dist/phases/pr-shared/__tests__/agent-utils.test.js +0 -91
- package/dist/phases/pr-shared/__tests__/context.test.d.ts +0 -1
- package/dist/phases/pr-shared/__tests__/context.test.js +0 -94
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.d.ts +0 -1
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.js +0 -331
- package/dist/phases/release-sync/__tests__/github.test.d.ts +0 -9
- package/dist/phases/release-sync/__tests__/github.test.js +0 -123
- package/dist/phases/release-sync/__tests__/snapshot.test.d.ts +0 -8
- package/dist/phases/release-sync/__tests__/snapshot.test.js +0 -93
- package/dist/phases/smoke-test/__tests__/agent.test.d.ts +0 -4
- package/dist/phases/smoke-test/__tests__/agent.test.js +0 -85
- package/dist/services/coaching/__tests__/coaching-agent.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/coaching-agent.test.js +0 -74
- package/dist/services/coaching/__tests__/coaching-loop.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/coaching-loop.test.js +0 -59
- package/dist/services/coaching/__tests__/self-rating.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/self-rating.test.js +0 -188
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.js +0 -122
- package/dist/services/phase-hooks/__tests__/hook-executor.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/hook-executor.test.js +0 -321
- package/dist/services/phase-hooks/__tests__/hook-runner.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/hook-runner.test.js +0 -261
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.js +0 -158
- package/dist/services/video/__tests__/video-pipeline.test.d.ts +0 -6
- package/dist/services/video/__tests__/video-pipeline.test.js +0 -249
- package/dist/workspace/__tests__/workspace-manager.test.d.ts +0 -7
- package/dist/workspace/__tests__/workspace-manager.test.js +0 -52
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { buildImprovementPrompt, } from '../coaching-agent.js';
|
|
4
|
-
void describe('buildImprovementPrompt', () => {
|
|
5
|
-
const decision = {
|
|
6
|
-
shouldContinue: true,
|
|
7
|
-
reasoning: 'Completeness is weak, needs more coverage',
|
|
8
|
-
focusAreas: ['completeness', 'accuracy'],
|
|
9
|
-
suggestions: [
|
|
10
|
-
'Add error handling section',
|
|
11
|
-
'Include database migration plan',
|
|
12
|
-
],
|
|
13
|
-
};
|
|
14
|
-
const rating = {
|
|
15
|
-
score: 72,
|
|
16
|
-
summary: 'Decent but incomplete',
|
|
17
|
-
criteria_scores: {
|
|
18
|
-
completeness: { score: 60, reason: 'Missing sections' },
|
|
19
|
-
accuracy: { score: 75, reason: 'Minor issues' },
|
|
20
|
-
quality: { score: 82, reason: 'Good structure' },
|
|
21
|
-
},
|
|
22
|
-
strengths: ['Clean structure'],
|
|
23
|
-
weaknesses: ['Missing error handling', 'No migration plan'],
|
|
24
|
-
};
|
|
25
|
-
void it('includes current score and target', () => {
|
|
26
|
-
const prompt = buildImprovementPrompt(decision, rating);
|
|
27
|
-
assert.ok(prompt.includes('72/100'));
|
|
28
|
-
assert.ok(prompt.includes('100/100'));
|
|
29
|
-
});
|
|
30
|
-
void it('includes coaching reasoning', () => {
|
|
31
|
-
const prompt = buildImprovementPrompt(decision, rating);
|
|
32
|
-
assert.ok(prompt.includes('Completeness is weak, needs more coverage'));
|
|
33
|
-
});
|
|
34
|
-
void it('includes focus areas with scores', () => {
|
|
35
|
-
const prompt = buildImprovementPrompt(decision, rating);
|
|
36
|
-
assert.ok(prompt.includes('completeness'));
|
|
37
|
-
assert.ok(prompt.includes('60/100'));
|
|
38
|
-
assert.ok(prompt.includes('accuracy'));
|
|
39
|
-
assert.ok(prompt.includes('75/100'));
|
|
40
|
-
});
|
|
41
|
-
void it('includes specific suggestions', () => {
|
|
42
|
-
const prompt = buildImprovementPrompt(decision, rating);
|
|
43
|
-
assert.ok(prompt.includes('Add error handling section'));
|
|
44
|
-
assert.ok(prompt.includes('Include database migration plan'));
|
|
45
|
-
});
|
|
46
|
-
void it('includes weaknesses to address', () => {
|
|
47
|
-
const prompt = buildImprovementPrompt(decision, rating);
|
|
48
|
-
assert.ok(prompt.includes('Missing error handling'));
|
|
49
|
-
assert.ok(prompt.includes('No migration plan'));
|
|
50
|
-
});
|
|
51
|
-
void it('handles empty focus areas gracefully', () => {
|
|
52
|
-
const emptyDecision = {
|
|
53
|
-
shouldContinue: true,
|
|
54
|
-
reasoning: 'General improvement needed',
|
|
55
|
-
focusAreas: [],
|
|
56
|
-
suggestions: ['Improve overall'],
|
|
57
|
-
};
|
|
58
|
-
const prompt = buildImprovementPrompt(emptyDecision, rating);
|
|
59
|
-
assert.ok(prompt.includes('General improvement needed'));
|
|
60
|
-
assert.ok(prompt.includes('Improve overall'));
|
|
61
|
-
});
|
|
62
|
-
void it('handles focus areas not present in criteria_scores', () => {
|
|
63
|
-
const decisionWithUnknown = {
|
|
64
|
-
shouldContinue: true,
|
|
65
|
-
reasoning: 'test',
|
|
66
|
-
focusAreas: ['nonexistent_criterion'],
|
|
67
|
-
suggestions: ['test'],
|
|
68
|
-
};
|
|
69
|
-
const prompt = buildImprovementPrompt(decisionWithUnknown, rating);
|
|
70
|
-
// Should not crash, should show '?' for missing score
|
|
71
|
-
assert.ok(prompt.includes('nonexistent_criterion'));
|
|
72
|
-
assert.ok(prompt.includes('?/100'));
|
|
73
|
-
});
|
|
74
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { isStagnant } from '../coaching-loop.js';
|
|
4
|
-
function makeRating(score) {
|
|
5
|
-
return {
|
|
6
|
-
score,
|
|
7
|
-
summary: `Score: ${score}`,
|
|
8
|
-
criteria_scores: {},
|
|
9
|
-
strengths: [],
|
|
10
|
-
weaknesses: [],
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
void describe('isStagnant', () => {
|
|
14
|
-
void it('returns false when fewer than 3 ratings', () => {
|
|
15
|
-
assert.strictEqual(isStagnant([]), false);
|
|
16
|
-
assert.strictEqual(isStagnant([makeRating(50)]), false);
|
|
17
|
-
assert.strictEqual(isStagnant([makeRating(50), makeRating(52)]), false);
|
|
18
|
-
});
|
|
19
|
-
void it('returns true when 3 ratings with < 3 point improvement', () => {
|
|
20
|
-
const ratings = [makeRating(80), makeRating(81), makeRating(82)];
|
|
21
|
-
assert.strictEqual(isStagnant(ratings), true);
|
|
22
|
-
});
|
|
23
|
-
void it('returns true when 3 ratings with zero improvement', () => {
|
|
24
|
-
const ratings = [makeRating(85), makeRating(85), makeRating(85)];
|
|
25
|
-
assert.strictEqual(isStagnant(ratings), true);
|
|
26
|
-
});
|
|
27
|
-
void it('returns false when improvement >= 3 points', () => {
|
|
28
|
-
// 73 - 70 = 3, and MIN_IMPROVEMENT = 3, so 3 < 3 is false → not stagnant
|
|
29
|
-
const ratings = [makeRating(70), makeRating(72), makeRating(73)];
|
|
30
|
-
assert.strictEqual(isStagnant(ratings), false);
|
|
31
|
-
});
|
|
32
|
-
void it('returns false when improvement exactly equals threshold', () => {
|
|
33
|
-
const ratings = [makeRating(70), makeRating(72), makeRating(73)];
|
|
34
|
-
// improvement = 73 - 70 = 3, MIN_IMPROVEMENT = 3
|
|
35
|
-
// 3 < 3 is false → not stagnant
|
|
36
|
-
assert.strictEqual(isStagnant(ratings), false);
|
|
37
|
-
});
|
|
38
|
-
void it('returns false when improvement exceeds threshold', () => {
|
|
39
|
-
const ratings = [makeRating(60), makeRating(65), makeRating(70)];
|
|
40
|
-
assert.strictEqual(isStagnant(ratings), false);
|
|
41
|
-
});
|
|
42
|
-
void it('only looks at last STAGNATION_WINDOW ratings', () => {
|
|
43
|
-
// Early ratings had big jumps, but last 3 are flat
|
|
44
|
-
const ratings = [
|
|
45
|
-
makeRating(30),
|
|
46
|
-
makeRating(50),
|
|
47
|
-
makeRating(70),
|
|
48
|
-
makeRating(71),
|
|
49
|
-
makeRating(72),
|
|
50
|
-
];
|
|
51
|
-
// Last 3: 70, 71, 72 → improvement = 2 < 3 → stagnant
|
|
52
|
-
assert.strictEqual(isStagnant(ratings), true);
|
|
53
|
-
});
|
|
54
|
-
void it('handles decreasing scores as stagnant', () => {
|
|
55
|
-
const ratings = [makeRating(80), makeRating(78), makeRating(79)];
|
|
56
|
-
// improvement = 79 - 80 = -1 < 3 → stagnant
|
|
57
|
-
assert.strictEqual(isStagnant(ratings), true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { buildSelfRatingPrompt, getCriteriaForPhase, parseSelfRating, } from '../self-rating.js';
|
|
4
|
-
void describe('getCriteriaForPhase', () => {
|
|
5
|
-
void it('returns analysis criteria for feature_analysis', () => {
|
|
6
|
-
const criteria = getCriteriaForPhase('feature_analysis');
|
|
7
|
-
assert.ok(criteria.includes('coverage'));
|
|
8
|
-
assert.ok(criteria.includes('clarity'));
|
|
9
|
-
assert.ok(criteria.includes('completeness'));
|
|
10
|
-
});
|
|
11
|
-
void it('returns analysis criteria for user_stories_analysis', () => {
|
|
12
|
-
const criteria = getCriteriaForPhase('user_stories_analysis');
|
|
13
|
-
assert.ok(criteria.includes('coverage'));
|
|
14
|
-
});
|
|
15
|
-
void it('returns analysis criteria for test_cases_analysis', () => {
|
|
16
|
-
const criteria = getCriteriaForPhase('test_cases_analysis');
|
|
17
|
-
assert.ok(criteria.includes('clarity'));
|
|
18
|
-
});
|
|
19
|
-
void it('returns design criteria for technical_design', () => {
|
|
20
|
-
const criteria = getCriteriaForPhase('technical_design');
|
|
21
|
-
assert.ok(criteria.includes('feasibility'));
|
|
22
|
-
assert.ok(criteria.includes('scalability'));
|
|
23
|
-
assert.ok(criteria.includes('maintainability'));
|
|
24
|
-
});
|
|
25
|
-
void it('returns design criteria for branch_planning', () => {
|
|
26
|
-
const criteria = getCriteriaForPhase('branch_planning');
|
|
27
|
-
assert.ok(criteria.includes('feasibility'));
|
|
28
|
-
});
|
|
29
|
-
void it('returns code criteria for code_implementation', () => {
|
|
30
|
-
const criteria = getCriteriaForPhase('code_implementation');
|
|
31
|
-
assert.ok(criteria.includes('readability'));
|
|
32
|
-
assert.ok(criteria.includes('testability'));
|
|
33
|
-
assert.ok(criteria.includes('performance'));
|
|
34
|
-
assert.ok(criteria.includes('security'));
|
|
35
|
-
});
|
|
36
|
-
void it('returns code criteria for code_refine', () => {
|
|
37
|
-
const criteria = getCriteriaForPhase('code_refine');
|
|
38
|
-
assert.ok(criteria.includes('readability'));
|
|
39
|
-
});
|
|
40
|
-
void it('returns common criteria for autonomous', () => {
|
|
41
|
-
const criteria = getCriteriaForPhase('autonomous');
|
|
42
|
-
assert.ok(criteria.includes('completeness'));
|
|
43
|
-
assert.ok(criteria.includes('accuracy'));
|
|
44
|
-
assert.ok(criteria.includes('quality'));
|
|
45
|
-
assert.ok(criteria.includes('consistency'));
|
|
46
|
-
});
|
|
47
|
-
void it('all criteria sets include common criteria', () => {
|
|
48
|
-
const phases = [
|
|
49
|
-
'feature_analysis',
|
|
50
|
-
'technical_design',
|
|
51
|
-
'code_implementation',
|
|
52
|
-
'autonomous',
|
|
53
|
-
];
|
|
54
|
-
for (const phase of phases) {
|
|
55
|
-
const criteria = getCriteriaForPhase(phase);
|
|
56
|
-
assert.ok(criteria.includes('completeness'), `${phase} missing completeness`);
|
|
57
|
-
assert.ok(criteria.includes('accuracy'), `${phase} missing accuracy`);
|
|
58
|
-
assert.ok(criteria.includes('quality'), `${phase} missing quality`);
|
|
59
|
-
assert.ok(criteria.includes('consistency'), `${phase} missing consistency`);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
void describe('buildSelfRatingPrompt', () => {
|
|
64
|
-
void it('includes phase-specific criteria', () => {
|
|
65
|
-
const prompt = buildSelfRatingPrompt('technical_design');
|
|
66
|
-
assert.ok(prompt.includes('"feasibility"'));
|
|
67
|
-
assert.ok(prompt.includes('"scalability"'));
|
|
68
|
-
assert.ok(prompt.includes('"maintainability"'));
|
|
69
|
-
});
|
|
70
|
-
void it('includes JSON structure template', () => {
|
|
71
|
-
const prompt = buildSelfRatingPrompt('code_implementation');
|
|
72
|
-
assert.ok(prompt.includes('"self_rating"'));
|
|
73
|
-
assert.ok(prompt.includes('"score"'));
|
|
74
|
-
assert.ok(prompt.includes('"criteria_scores"'));
|
|
75
|
-
assert.ok(prompt.includes('"strengths"'));
|
|
76
|
-
assert.ok(prompt.includes('"weaknesses"'));
|
|
77
|
-
});
|
|
78
|
-
void it('asks for 0-100 scores', () => {
|
|
79
|
-
const prompt = buildSelfRatingPrompt('feature_analysis');
|
|
80
|
-
assert.ok(prompt.includes('0-100'));
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
void describe('parseSelfRating', () => {
|
|
84
|
-
void it('parses valid JSON in markdown code block', () => {
|
|
85
|
-
const response = `Here is my self-rating:
|
|
86
|
-
|
|
87
|
-
\`\`\`json
|
|
88
|
-
{
|
|
89
|
-
"self_rating": {
|
|
90
|
-
"score": 85,
|
|
91
|
-
"summary": "Good coverage but some gaps",
|
|
92
|
-
"criteria_scores": {
|
|
93
|
-
"completeness": { "score": 90, "reason": "Covered all cases" },
|
|
94
|
-
"accuracy": { "score": 80, "reason": "Minor issues" }
|
|
95
|
-
},
|
|
96
|
-
"strengths": ["Good structure", "Clear naming"],
|
|
97
|
-
"weaknesses": ["Missing edge cases"]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
\`\`\``;
|
|
101
|
-
const rating = parseSelfRating(response, 'technical_design');
|
|
102
|
-
assert.ok(rating);
|
|
103
|
-
assert.strictEqual(rating.score, 85);
|
|
104
|
-
assert.strictEqual(rating.summary, 'Good coverage but some gaps');
|
|
105
|
-
assert.strictEqual(rating.criteria_scores.completeness.score, 90);
|
|
106
|
-
assert.strictEqual(rating.criteria_scores.accuracy.score, 80);
|
|
107
|
-
assert.deepStrictEqual(rating.strengths, ['Good structure', 'Clear naming']);
|
|
108
|
-
assert.deepStrictEqual(rating.weaknesses, ['Missing edge cases']);
|
|
109
|
-
});
|
|
110
|
-
void it('parses raw JSON without code block', () => {
|
|
111
|
-
const response = JSON.stringify({
|
|
112
|
-
self_rating: {
|
|
113
|
-
score: 72,
|
|
114
|
-
summary: 'Needs work',
|
|
115
|
-
criteria_scores: {},
|
|
116
|
-
strengths: [],
|
|
117
|
-
weaknesses: ['Poor coverage'],
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
const rating = parseSelfRating(response, 'feature_analysis');
|
|
121
|
-
assert.ok(rating);
|
|
122
|
-
assert.strictEqual(rating.score, 72);
|
|
123
|
-
assert.strictEqual(rating.summary, 'Needs work');
|
|
124
|
-
});
|
|
125
|
-
void it('rounds score to integer', () => {
|
|
126
|
-
const response = JSON.stringify({
|
|
127
|
-
self_rating: {
|
|
128
|
-
score: 85.7,
|
|
129
|
-
summary: 'test',
|
|
130
|
-
criteria_scores: {},
|
|
131
|
-
strengths: [],
|
|
132
|
-
weaknesses: [],
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
const rating = parseSelfRating(response, 'technical_design');
|
|
136
|
-
assert.ok(rating);
|
|
137
|
-
assert.strictEqual(rating.score, 86);
|
|
138
|
-
});
|
|
139
|
-
void it('returns null for invalid score above 100', () => {
|
|
140
|
-
const response = JSON.stringify({
|
|
141
|
-
self_rating: {
|
|
142
|
-
score: 150,
|
|
143
|
-
summary: 'test',
|
|
144
|
-
criteria_scores: {},
|
|
145
|
-
strengths: [],
|
|
146
|
-
weaknesses: [],
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
const rating = parseSelfRating(response, 'technical_design');
|
|
150
|
-
assert.strictEqual(rating, null);
|
|
151
|
-
});
|
|
152
|
-
void it('returns null for negative score', () => {
|
|
153
|
-
const response = JSON.stringify({
|
|
154
|
-
self_rating: {
|
|
155
|
-
score: -5,
|
|
156
|
-
summary: 'test',
|
|
157
|
-
criteria_scores: {},
|
|
158
|
-
strengths: [],
|
|
159
|
-
weaknesses: [],
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
const rating = parseSelfRating(response, 'technical_design');
|
|
163
|
-
assert.strictEqual(rating, null);
|
|
164
|
-
});
|
|
165
|
-
void it('returns null for non-JSON response', () => {
|
|
166
|
-
const rating = parseSelfRating('This is not JSON at all', 'technical_design');
|
|
167
|
-
assert.strictEqual(rating, null);
|
|
168
|
-
});
|
|
169
|
-
void it('returns null for empty response', () => {
|
|
170
|
-
const rating = parseSelfRating('', 'technical_design');
|
|
171
|
-
assert.strictEqual(rating, null);
|
|
172
|
-
});
|
|
173
|
-
void it('handles missing optional fields gracefully', () => {
|
|
174
|
-
const response = JSON.stringify({
|
|
175
|
-
self_rating: {
|
|
176
|
-
score: 60,
|
|
177
|
-
criteria_scores: { completeness: { score: 60, reason: 'ok' } },
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
const rating = parseSelfRating(response, 'technical_design');
|
|
181
|
-
assert.ok(rating);
|
|
182
|
-
assert.strictEqual(rating.score, 60);
|
|
183
|
-
assert.strictEqual(rating.summary, '');
|
|
184
|
-
assert.deepStrictEqual(rating.strengths, []);
|
|
185
|
-
assert.deepStrictEqual(rating.weaknesses, []);
|
|
186
|
-
assert.strictEqual(rating.criteria_scores.completeness.score, 60);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { afterEach, describe, it } from 'node:test';
|
|
3
|
-
import { cacheBindings, clearBindingsCache, getBindingsForPhase, getCachedBindings, } from '../bindings-fetcher.js';
|
|
4
|
-
function makeBinding(overrides = {}) {
|
|
5
|
-
return {
|
|
6
|
-
id: 'hook-1',
|
|
7
|
-
product_id: 'prod-1',
|
|
8
|
-
phase: 'technical-design',
|
|
9
|
-
hook_point: 'after',
|
|
10
|
-
plugin_name: 'payload-cms',
|
|
11
|
-
skill_name: 'validate-schema',
|
|
12
|
-
on_failure: 'block',
|
|
13
|
-
config: {},
|
|
14
|
-
sort_order: 0,
|
|
15
|
-
enabled: true,
|
|
16
|
-
...overrides,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
// ---- getBindingsForPhase ----
|
|
20
|
-
void describe('getBindingsForPhase', () => {
|
|
21
|
-
void it('filters by exact phase match', () => {
|
|
22
|
-
const bindings = [
|
|
23
|
-
makeBinding({ phase: 'technical-design', hook_point: 'after' }),
|
|
24
|
-
makeBinding({
|
|
25
|
-
id: '2',
|
|
26
|
-
phase: 'code-implementation',
|
|
27
|
-
hook_point: 'after',
|
|
28
|
-
}),
|
|
29
|
-
];
|
|
30
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'after');
|
|
31
|
-
assert.strictEqual(result.length, 1);
|
|
32
|
-
assert.strictEqual(result[0].phase, 'technical-design');
|
|
33
|
-
});
|
|
34
|
-
void it('matches wildcard phase "*"', () => {
|
|
35
|
-
const bindings = [
|
|
36
|
-
makeBinding({ phase: '*', hook_point: 'after', skill_name: 'notify' }),
|
|
37
|
-
];
|
|
38
|
-
const result = getBindingsForPhase(bindings, 'code-review', 'after');
|
|
39
|
-
assert.strictEqual(result.length, 1);
|
|
40
|
-
assert.strictEqual(result[0].skill_name, 'notify');
|
|
41
|
-
});
|
|
42
|
-
void it('combines exact match and wildcard', () => {
|
|
43
|
-
const bindings = [
|
|
44
|
-
makeBinding({
|
|
45
|
-
id: '1',
|
|
46
|
-
phase: 'technical-design',
|
|
47
|
-
hook_point: 'after',
|
|
48
|
-
sort_order: 1,
|
|
49
|
-
}),
|
|
50
|
-
makeBinding({ id: '2', phase: '*', hook_point: 'after', sort_order: 0 }),
|
|
51
|
-
];
|
|
52
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'after');
|
|
53
|
-
assert.strictEqual(result.length, 2);
|
|
54
|
-
// Wildcard (sort_order 0) comes first
|
|
55
|
-
assert.strictEqual(result[0].id, '2');
|
|
56
|
-
assert.strictEqual(result[1].id, '1');
|
|
57
|
-
});
|
|
58
|
-
void it('filters by hook_point', () => {
|
|
59
|
-
const bindings = [
|
|
60
|
-
makeBinding({ hook_point: 'before' }),
|
|
61
|
-
makeBinding({ id: '2', hook_point: 'after' }),
|
|
62
|
-
];
|
|
63
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'before');
|
|
64
|
-
assert.strictEqual(result.length, 1);
|
|
65
|
-
assert.strictEqual(result[0].hook_point, 'before');
|
|
66
|
-
});
|
|
67
|
-
void it('excludes disabled bindings', () => {
|
|
68
|
-
const bindings = [makeBinding({ enabled: false })];
|
|
69
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'after');
|
|
70
|
-
assert.strictEqual(result.length, 0);
|
|
71
|
-
});
|
|
72
|
-
void it('sorts by sort_order ascending', () => {
|
|
73
|
-
const bindings = [
|
|
74
|
-
makeBinding({ id: 'c', sort_order: 10 }),
|
|
75
|
-
makeBinding({ id: 'a', sort_order: 1 }),
|
|
76
|
-
makeBinding({ id: 'b', sort_order: 5 }),
|
|
77
|
-
];
|
|
78
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'after');
|
|
79
|
-
assert.deepStrictEqual(result.map((b) => b.id), ['a', 'b', 'c']);
|
|
80
|
-
});
|
|
81
|
-
void it('returns empty array when no bindings match', () => {
|
|
82
|
-
const bindings = [
|
|
83
|
-
makeBinding({ phase: 'code-review', hook_point: 'before' }),
|
|
84
|
-
];
|
|
85
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'after');
|
|
86
|
-
assert.strictEqual(result.length, 0);
|
|
87
|
-
});
|
|
88
|
-
void it('handles on_error hook point', () => {
|
|
89
|
-
const bindings = [makeBinding({ hook_point: 'on_error' })];
|
|
90
|
-
const result = getBindingsForPhase(bindings, 'technical-design', 'on_error');
|
|
91
|
-
assert.strictEqual(result.length, 1);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
// ---- Cache management ----
|
|
95
|
-
void describe('bindings cache', () => {
|
|
96
|
-
afterEach(() => {
|
|
97
|
-
clearBindingsCache('test-feature-1');
|
|
98
|
-
clearBindingsCache('test-feature-2');
|
|
99
|
-
});
|
|
100
|
-
void it('returns null for uncached feature', () => {
|
|
101
|
-
assert.strictEqual(getCachedBindings('nonexistent'), null);
|
|
102
|
-
});
|
|
103
|
-
void it('round-trips cache/get/clear', () => {
|
|
104
|
-
const bindings = [makeBinding()];
|
|
105
|
-
cacheBindings('test-feature-1', 'prod-1', bindings);
|
|
106
|
-
const cached = getCachedBindings('test-feature-1');
|
|
107
|
-
assert.ok(cached);
|
|
108
|
-
assert.strictEqual(cached.productId, 'prod-1');
|
|
109
|
-
assert.strictEqual(cached.bindings.length, 1);
|
|
110
|
-
assert.ok(cached.fetchedAt > 0);
|
|
111
|
-
clearBindingsCache('test-feature-1');
|
|
112
|
-
assert.strictEqual(getCachedBindings('test-feature-1'), null);
|
|
113
|
-
});
|
|
114
|
-
void it('isolates cache by featureId', () => {
|
|
115
|
-
cacheBindings('test-feature-1', 'prod-1', [makeBinding({ id: 'a' })]);
|
|
116
|
-
cacheBindings('test-feature-2', 'prod-2', [makeBinding({ id: 'b' })]);
|
|
117
|
-
const cached1 = getCachedBindings('test-feature-1');
|
|
118
|
-
const cached2 = getCachedBindings('test-feature-2');
|
|
119
|
-
assert.strictEqual(cached1?.bindings[0].id, 'a');
|
|
120
|
-
assert.strictEqual(cached2?.bindings[0].id, 'b');
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|