fraim-framework 2.0.123 → 2.0.124
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.
|
@@ -20,31 +20,25 @@
|
|
|
20
20
|
* seekMentoring handler (e.g., when the local AIMentor errors).
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.REQUIRED_QUALITY_FIELDS = exports.ALL_STAGE_CATEGORIES = exports.STAGE_DISPLAY_NAMES = exports.STAGE_CATEGORY_MAP = exports.QUALITY_PRODUCING_JOBS = exports.QUALITY_REGISTRY = void 0;
|
|
23
|
+
exports.REQUIRED_QUALITY_FIELDS = exports.ALL_STAGE_CATEGORIES = exports.STAGE_DISPLAY_NAMES = exports.STAGE_CATEGORY_MAP = exports.QUALITY_GATE_JOBS = exports.QUALITY_SCORE_JOBS = exports.QUALITY_PRODUCING_JOBS = exports.QUALITY_REGISTRY = void 0;
|
|
24
24
|
exports.getRequiredFieldsForJob = getRequiredFieldsForJob;
|
|
25
25
|
exports.validateQualityEvidence = validateQualityEvidence;
|
|
26
26
|
exports.buildQualityRejectionMessage = buildQualityRejectionMessage;
|
|
27
|
-
/**
|
|
28
|
-
* Central registry of FRAIM jobs that interact with the quality telemetry system.
|
|
29
|
-
* This is the SINGLE SOURCE OF TRUTH for:
|
|
30
|
-
* 1. Stage mapping (where it appears on the dashboard).
|
|
31
|
-
* 2. Enforcement (whether it MUST emit a quality score to complete).
|
|
32
|
-
*/
|
|
33
27
|
exports.QUALITY_REGISTRY = {
|
|
34
28
|
// Customer Development
|
|
35
|
-
'process-interview-notes': { stage: 'customer-development', enforced: true },
|
|
36
|
-
'triage-customer-needs': { stage: 'customer-development', enforced: true },
|
|
29
|
+
'process-interview-notes': { stage: 'customer-development', enforced: true, telemetryKind: 'score' },
|
|
30
|
+
'triage-customer-needs': { stage: 'customer-development', enforced: true, telemetryKind: 'gate' },
|
|
37
31
|
'interview-preparation': { stage: 'customer-discovery', enforced: false },
|
|
38
32
|
// Business Strategy
|
|
39
|
-
'review-business-strategy': { stage: 'business-strategy', enforced: true },
|
|
33
|
+
'review-business-strategy': { stage: 'business-strategy', enforced: true, telemetryKind: 'score' },
|
|
40
34
|
'business-plan-creation': { stage: 'business-strategy', enforced: false },
|
|
41
|
-
'branding-quality-audit': { stage: 'branding', enforced: true },
|
|
35
|
+
'branding-quality-audit': { stage: 'branding', enforced: true, telemetryKind: 'score' },
|
|
42
36
|
// Product Quality
|
|
43
|
-
'code-quality-assessment': { stage: 'product-quality', enforced: true },
|
|
37
|
+
'code-quality-assessment': { stage: 'product-quality', enforced: true, telemetryKind: 'score' },
|
|
44
38
|
// Test Quality
|
|
45
|
-
'test-quality-assessment': { stage: 'test-quality', enforced: true },
|
|
39
|
+
'test-quality-assessment': { stage: 'test-quality', enforced: true, telemetryKind: 'score' },
|
|
46
40
|
// Security
|
|
47
|
-
'security-review': { stage: 'security', enforced: true },
|
|
41
|
+
'security-review': { stage: 'security', enforced: true, telemetryKind: 'score' },
|
|
48
42
|
// Fundraising
|
|
49
43
|
'investor-pitch-preparation': { stage: 'fundraising', enforced: false },
|
|
50
44
|
// Go-to-Market
|
|
@@ -55,6 +49,15 @@ exports.QUALITY_REGISTRY = {
|
|
|
55
49
|
* Derived enforcement list for backward compatibility.
|
|
56
50
|
*/
|
|
57
51
|
exports.QUALITY_PRODUCING_JOBS = Object.keys(exports.QUALITY_REGISTRY).filter((job) => exports.QUALITY_REGISTRY[job].enforced);
|
|
52
|
+
/**
|
|
53
|
+
* Jobs that write scored review rows used by the Quality tab scorecards.
|
|
54
|
+
* Gate-only telemetry jobs (for example `triage-customer-needs`) are excluded.
|
|
55
|
+
*/
|
|
56
|
+
exports.QUALITY_SCORE_JOBS = Object.keys(exports.QUALITY_REGISTRY).filter((job) => exports.QUALITY_REGISTRY[job].enforced && exports.QUALITY_REGISTRY[job].telemetryKind !== 'gate');
|
|
57
|
+
/**
|
|
58
|
+
* Jobs that emit gate-style telemetry without a composite score.
|
|
59
|
+
*/
|
|
60
|
+
exports.QUALITY_GATE_JOBS = Object.keys(exports.QUALITY_REGISTRY).filter((job) => exports.QUALITY_REGISTRY[job].enforced && exports.QUALITY_REGISTRY[job].telemetryKind === 'gate');
|
|
58
61
|
/**
|
|
59
62
|
* @deprecated Use QUALITY_REGISTRY for new code.
|
|
60
63
|
* Derived stage mappings for backward compatibility.
|
|
@@ -97,6 +100,12 @@ const CUSTOMER_DEV_REQUIRED_FIELDS = [
|
|
|
97
100
|
{ path: 'participant.authority', type: 'number' },
|
|
98
101
|
{ path: 'evidence.quoteSpecificityAvg', type: 'number' }
|
|
99
102
|
];
|
|
103
|
+
/**
|
|
104
|
+
* Gate-only customer development jobs emit a decision without a composite score.
|
|
105
|
+
*/
|
|
106
|
+
const GATE_REQUIRED_FIELDS = [
|
|
107
|
+
{ path: 'gateDecision', type: 'string' }
|
|
108
|
+
];
|
|
100
109
|
/**
|
|
101
110
|
* Required fields for all other quality-producing jobs.
|
|
102
111
|
* Only composite and coaching are universally required — sub-dimensions
|
|
@@ -112,6 +121,9 @@ const UNIVERSAL_REQUIRED_FIELDS = [
|
|
|
112
121
|
*/
|
|
113
122
|
function getRequiredFieldsForJob(jobName) {
|
|
114
123
|
const entry = exports.QUALITY_REGISTRY[jobName];
|
|
124
|
+
if (entry?.telemetryKind === 'gate') {
|
|
125
|
+
return GATE_REQUIRED_FIELDS;
|
|
126
|
+
}
|
|
115
127
|
if (entry?.stage === 'customer-development') {
|
|
116
128
|
return CUSTOMER_DEV_REQUIRED_FIELDS;
|
|
117
129
|
}
|
|
@@ -174,38 +186,53 @@ function validateQualityEvidence(quality, jobName) {
|
|
|
174
186
|
function buildQualityRejectionMessage(jobName, currentPhase, errors) {
|
|
175
187
|
const errorBullets = errors.map(e => `- ${e}`).join('\n');
|
|
176
188
|
const entry = exports.QUALITY_REGISTRY[jobName];
|
|
189
|
+
const isGateOnly = entry?.telemetryKind === 'gate';
|
|
177
190
|
const isCustomerDev = entry?.stage === 'customer-development';
|
|
178
|
-
const schemaExample =
|
|
191
|
+
const schemaExample = isGateOnly
|
|
179
192
|
? [
|
|
180
193
|
'```javascript',
|
|
181
194
|
'evidence: {',
|
|
182
195
|
' quality: {',
|
|
183
|
-
'
|
|
184
|
-
'
|
|
185
|
-
'
|
|
186
|
-
'
|
|
187
|
-
'
|
|
188
|
-
' },',
|
|
189
|
-
' coaching: "<actionable recommendation>",',
|
|
190
|
-
' interviewee: "<name>",',
|
|
191
|
-
' company: "<company>"',
|
|
196
|
+
' gateDecision: "<pass|flag|fail>",',
|
|
197
|
+
' interviewsAnalyzed: <number>,',
|
|
198
|
+
' distinctPainPatterns: <number>,',
|
|
199
|
+
' gaps: ["<gap summary>"],',
|
|
200
|
+
' coaching: "<actionable recommendation>"',
|
|
192
201
|
' }',
|
|
193
202
|
'}',
|
|
194
203
|
'```'
|
|
195
204
|
]
|
|
196
|
-
:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
: isCustomerDev
|
|
206
|
+
? [
|
|
207
|
+
'```javascript',
|
|
208
|
+
'evidence: {',
|
|
209
|
+
' quality: {',
|
|
210
|
+
' composite: <number 0-10>,',
|
|
211
|
+
' participant: { fit: <number 1-10>, urgency: <number 1-10>, authority: <number 1-10> },',
|
|
212
|
+
' evidence: {',
|
|
213
|
+
' quoteSpecificityAvg: <number 1-10>',
|
|
214
|
+
' // other fields are allowed and encouraged but not required',
|
|
215
|
+
' },',
|
|
216
|
+
' coaching: "<actionable recommendation>",',
|
|
217
|
+
' interviewee: "<name>",',
|
|
218
|
+
' company: "<company>"',
|
|
219
|
+
' }',
|
|
220
|
+
'}',
|
|
221
|
+
'```'
|
|
222
|
+
]
|
|
223
|
+
: [
|
|
224
|
+
'```javascript',
|
|
225
|
+
'evidence: {',
|
|
226
|
+
' quality: {',
|
|
227
|
+
' composite: <number 0-10>,',
|
|
228
|
+
' coaching: "<actionable recommendation>",',
|
|
229
|
+
' marketEvidence: { score: <number>, rationale: "<string>" }, // flat, NO "dimensions" wrapper',
|
|
230
|
+
' unitEconomics: { score: <number>, rationale: "<string>" },',
|
|
231
|
+
' // add other sub-scores as direct properties',
|
|
232
|
+
' }',
|
|
233
|
+
'}',
|
|
234
|
+
'```'
|
|
235
|
+
];
|
|
209
236
|
const importantNote = [
|
|
210
237
|
'',
|
|
211
238
|
'> [!IMPORTANT]',
|
|
@@ -1689,12 +1689,21 @@ class FraimLocalMCPServer {
|
|
|
1689
1689
|
return await this.finalizeLocalToolTextResponse(request, requestSessionId, requestId, rejection);
|
|
1690
1690
|
}
|
|
1691
1691
|
// Valid payload. Emit to the remote asynchronously.
|
|
1692
|
+
if (!this.repoInfo) {
|
|
1693
|
+
this.detectRepoInfo();
|
|
1694
|
+
}
|
|
1692
1695
|
this.emitQualityScoreToRemote({
|
|
1693
1696
|
jobName: args.jobName,
|
|
1694
1697
|
jobId: args.jobId,
|
|
1695
1698
|
sessionId: requestSessionId || args.sessionId || 'unknown',
|
|
1696
1699
|
quality: args.evidence.quality,
|
|
1697
|
-
artifactPath: args.evidence.quality.artifactPath
|
|
1700
|
+
artifactPath: args.evidence.quality.artifactPath,
|
|
1701
|
+
repoIdentifier: args.evidence?.reviewContext?.repoIdentifier || this.repoInfo?.url,
|
|
1702
|
+
reviewContext: {
|
|
1703
|
+
...(args.evidence?.reviewContext || {}),
|
|
1704
|
+
repoIdentifier: args.evidence?.reviewContext?.repoIdentifier || this.repoInfo?.url,
|
|
1705
|
+
branchRef: args.evidence?.reviewContext?.branchRef || this.repoInfo?.branch
|
|
1706
|
+
}
|
|
1698
1707
|
}).catch((err) => {
|
|
1699
1708
|
// Best-effort: log but never fail the user-facing response.
|
|
1700
1709
|
this.log(`⚠️ Quality score emission failed: ${err?.message || err}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-framework",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.124",
|
|
4
4
|
"description": "FRAIM: AI Workforce Infrastructure — the organizational capability that turns AI agents into an accountable workforce, their operators into capable AI managers, and executives into leaders with clear optics on AI proficiency.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|