fraim 2.0.168 → 2.0.170
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/dist/src/ai-hub/server.js +51 -4
- package/dist/src/ai-hub/word-sideload.js +95 -0
- package/dist/src/cli/commands/test-mcp.js +171 -0
- package/dist/src/cli/setup/first-run.js +242 -0
- package/dist/src/core/config-writer.js +75 -0
- package/dist/src/core/utils/inheritance-parser.js +5 -0
- package/dist/src/core/utils/job-aliases.js +47 -0
- package/dist/src/core/utils/workflow-parser.js +174 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/public/ai-hub/powerpoint-taskpane/index.html +236 -236
- package/public/ai-hub/powerpoint-taskpane/manifest.xml +29 -29
- package/public/ai-hub/script.js +10 -8
- package/public/portfolio/ashley.html +1 -1
- package/public/portfolio/casey.html +1 -1
- package/public/portfolio/celia.html +1 -1
- package/public/portfolio/gautam.html +1 -1
- package/public/portfolio/hari.html +1 -1
- package/public/portfolio/maestro.html +1 -1
- package/public/portfolio/mandy.html +1 -1
- package/public/portfolio/pam.html +6 -6
- package/public/portfolio/qasm.html +1 -1
- package/public/portfolio/sade.html +1 -1
- package/public/portfolio/sam.html +1 -1
- package/public/portfolio/swen.html +6 -6
|
@@ -187,6 +187,11 @@ class InheritanceParser {
|
|
|
187
187
|
const parentMeta = JSON.parse(parentMatch[1]);
|
|
188
188
|
const mergedMeta = { ...parentMeta, ...childMeta };
|
|
189
189
|
delete mergedMeta.extends; // Remove extends from final merged content
|
|
190
|
+
// Deep-merge phase routing so child only overrides the entries it specifies;
|
|
191
|
+
// parent routing for untouched phases flows through unchanged.
|
|
192
|
+
if (parentMeta.phases && childMeta.phases) {
|
|
193
|
+
mergedMeta.phases = { ...parentMeta.phases, ...childMeta.phases };
|
|
194
|
+
}
|
|
190
195
|
// 2. Extract Body (everything after frontmatter)
|
|
191
196
|
const childBody = this.stripRedundantParentImports(child.substring(childMatch[0].length).trim(), typeof childMeta.extends === 'string' ? childMeta.extends : undefined);
|
|
192
197
|
const parentBody = parent.substring(parentMatch[0].length).trim();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEPRECATED_FRAIM_JOB_NAMES = void 0;
|
|
4
|
+
exports.resolveFraimJobName = resolveFraimJobName;
|
|
5
|
+
exports.isListableFraimJob = isListableFraimJob;
|
|
6
|
+
const DEPRECATED_TO_CANONICAL_JOB_MAP = {
|
|
7
|
+
'learn-and-scale': 'upskill-employee',
|
|
8
|
+
'model-behavior': 'upskill-employee',
|
|
9
|
+
'promote-learning': 'upskill-employee',
|
|
10
|
+
'refine-jobs': 'upskill-employee',
|
|
11
|
+
'refine-skills': 'upskill-employee'
|
|
12
|
+
};
|
|
13
|
+
const DIRECT_JOB_ALIASES = {
|
|
14
|
+
'sleep on learnings': 'sleep-on-learnings'
|
|
15
|
+
};
|
|
16
|
+
exports.DEPRECATED_FRAIM_JOB_NAMES = new Set(Object.keys(DEPRECATED_TO_CANONICAL_JOB_MAP));
|
|
17
|
+
function normalizeJobLookupInput(input) {
|
|
18
|
+
return input.trim().toLowerCase().replace(/[_\s]+/g, '-');
|
|
19
|
+
}
|
|
20
|
+
function resolveFraimJobName(input) {
|
|
21
|
+
const normalizedJobName = normalizeJobLookupInput(input);
|
|
22
|
+
const directAliasTarget = DIRECT_JOB_ALIASES[input.trim().toLowerCase()];
|
|
23
|
+
if (directAliasTarget) {
|
|
24
|
+
return {
|
|
25
|
+
requestedJobName: input,
|
|
26
|
+
normalizedJobName,
|
|
27
|
+
canonicalJobName: directAliasTarget
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const deprecatedAliasTarget = DEPRECATED_TO_CANONICAL_JOB_MAP[normalizedJobName];
|
|
31
|
+
if (deprecatedAliasTarget) {
|
|
32
|
+
return {
|
|
33
|
+
requestedJobName: input,
|
|
34
|
+
normalizedJobName,
|
|
35
|
+
canonicalJobName: deprecatedAliasTarget,
|
|
36
|
+
deprecatedAliasTarget
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
requestedJobName: input,
|
|
41
|
+
normalizedJobName,
|
|
42
|
+
canonicalJobName: normalizedJobName
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function isListableFraimJob(jobName) {
|
|
46
|
+
return !exports.DEPRECATED_FRAIM_JOB_NAMES.has(normalizeJobLookupInput(jobName));
|
|
47
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkflowParser = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
class WorkflowParser {
|
|
7
|
+
static extractMetadataBlock(content) {
|
|
8
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]+?)\r?\n---/);
|
|
9
|
+
if (frontmatterMatch) {
|
|
10
|
+
try {
|
|
11
|
+
return {
|
|
12
|
+
state: 'valid',
|
|
13
|
+
metadata: JSON.parse(frontmatterMatch[1]),
|
|
14
|
+
bodyStartIndex: frontmatterMatch[0].length
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return { state: 'invalid' };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const trimmedStart = content.search(/\S/);
|
|
22
|
+
if (trimmedStart === -1 || content[trimmedStart] !== '{') {
|
|
23
|
+
return { state: 'none' };
|
|
24
|
+
}
|
|
25
|
+
let depth = 0;
|
|
26
|
+
let inString = false;
|
|
27
|
+
let escaping = false;
|
|
28
|
+
for (let i = trimmedStart; i < content.length; i++) {
|
|
29
|
+
const ch = content[i];
|
|
30
|
+
if (inString) {
|
|
31
|
+
if (escaping) {
|
|
32
|
+
escaping = false;
|
|
33
|
+
}
|
|
34
|
+
else if (ch === '\\') {
|
|
35
|
+
escaping = true;
|
|
36
|
+
}
|
|
37
|
+
else if (ch === '"') {
|
|
38
|
+
inString = false;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (ch === '"') {
|
|
43
|
+
inString = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (ch === '{') {
|
|
47
|
+
depth++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (ch === '}') {
|
|
51
|
+
depth--;
|
|
52
|
+
if (depth === 0) {
|
|
53
|
+
const bodyStartIndex = i + 1;
|
|
54
|
+
const remainder = content.slice(bodyStartIndex).trimStart();
|
|
55
|
+
// `{...}\n---` is usually malformed frontmatter, not bare JSON metadata.
|
|
56
|
+
if (remainder.startsWith('---')) {
|
|
57
|
+
return { state: 'none' };
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
return {
|
|
61
|
+
state: 'valid',
|
|
62
|
+
metadata: JSON.parse(content.slice(trimmedStart, bodyStartIndex)),
|
|
63
|
+
bodyStartIndex
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { state: 'invalid' };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { state: 'none' };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse a workflow markdown file into a structured definition
|
|
76
|
+
* Supports three formats:
|
|
77
|
+
* 1. Phase-based workflows with JSON frontmatter
|
|
78
|
+
* 2. Phase-based workflows with bare leading JSON metadata
|
|
79
|
+
* 3. Simple workflows without metadata
|
|
80
|
+
*/
|
|
81
|
+
static parse(filePath) {
|
|
82
|
+
if (!(0, fs_1.existsSync)(filePath))
|
|
83
|
+
return null;
|
|
84
|
+
let content = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
85
|
+
if (content.charCodeAt(0) === 0xfeff) {
|
|
86
|
+
content = content.slice(1);
|
|
87
|
+
}
|
|
88
|
+
const metadataBlock = this.extractMetadataBlock(content);
|
|
89
|
+
if (metadataBlock.state === 'invalid') {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (metadataBlock.state === 'valid') {
|
|
93
|
+
return this.parsePhaseBasedWorkflow(filePath, content, metadataBlock.metadata, metadataBlock.bodyStartIndex);
|
|
94
|
+
}
|
|
95
|
+
return this.parseSimpleWorkflow(filePath, content);
|
|
96
|
+
}
|
|
97
|
+
static parsePhaseBasedWorkflow(filePath, content, metadata, bodyStartIndex) {
|
|
98
|
+
const contentAfterMetadata = content.substring(bodyStartIndex).trim();
|
|
99
|
+
const firstPhaseIndex = contentAfterMetadata.search(/^##\s+Phase:/m);
|
|
100
|
+
let overview = '';
|
|
101
|
+
let restOfContent = '';
|
|
102
|
+
if (firstPhaseIndex !== -1) {
|
|
103
|
+
overview = contentAfterMetadata.substring(0, firstPhaseIndex).trim();
|
|
104
|
+
restOfContent = contentAfterMetadata.substring(firstPhaseIndex);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
overview = contentAfterMetadata;
|
|
108
|
+
}
|
|
109
|
+
const phases = new Map();
|
|
110
|
+
const phaseSections = restOfContent.split(/^##\s+Phase:\s+/m);
|
|
111
|
+
if (!metadata.phases) {
|
|
112
|
+
metadata.phases = {};
|
|
113
|
+
}
|
|
114
|
+
for (let i = 1; i < phaseSections.length; i++) {
|
|
115
|
+
const section = phaseSections[i];
|
|
116
|
+
const sectionLines = section.split('\n');
|
|
117
|
+
const firstLine = sectionLines[0].trim();
|
|
118
|
+
const id = firstLine.split(/[ (]/)[0].trim().toLowerCase();
|
|
119
|
+
phases.set(id, `## Phase: ${section.trim()}`);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
metadata,
|
|
123
|
+
overview,
|
|
124
|
+
phases,
|
|
125
|
+
isSimple: false,
|
|
126
|
+
path: filePath
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
static parseSimpleWorkflow(filePath, content) {
|
|
130
|
+
const workflowName = (0, path_1.basename)(filePath, '.md');
|
|
131
|
+
const metadata = {
|
|
132
|
+
name: workflowName
|
|
133
|
+
};
|
|
134
|
+
return {
|
|
135
|
+
metadata,
|
|
136
|
+
overview: content.trim(),
|
|
137
|
+
phases: new Map(),
|
|
138
|
+
isSimple: true,
|
|
139
|
+
path: filePath
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
static parseContent(content, name, path) {
|
|
143
|
+
if (content.charCodeAt(0) === 0xfeff) {
|
|
144
|
+
content = content.slice(1);
|
|
145
|
+
}
|
|
146
|
+
const metadataBlock = this.extractMetadataBlock(content);
|
|
147
|
+
if (metadataBlock.state === 'invalid') {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
if (metadataBlock.state === 'valid') {
|
|
151
|
+
return this.parsePhaseBasedWorkflow(path || `content:${name}`, content, metadataBlock.metadata, metadataBlock.bodyStartIndex);
|
|
152
|
+
}
|
|
153
|
+
return this.parseSimpleWorkflow(path || `content:${name}`, content);
|
|
154
|
+
}
|
|
155
|
+
static getOverviewFromContent(content, name) {
|
|
156
|
+
const wf = this.parseContent(content, name);
|
|
157
|
+
return wf ? wf.overview : null;
|
|
158
|
+
}
|
|
159
|
+
static getOverview(filePath) {
|
|
160
|
+
const wf = this.parse(filePath);
|
|
161
|
+
return wf ? wf.overview : null;
|
|
162
|
+
}
|
|
163
|
+
static extractDescription(filePath) {
|
|
164
|
+
const wf = this.parse(filePath);
|
|
165
|
+
if (!wf)
|
|
166
|
+
return '';
|
|
167
|
+
const intentMatch = wf.overview.match(/## Intent\s+([\s\S]+?)(?:\r?\n##|$)/);
|
|
168
|
+
if (intentMatch)
|
|
169
|
+
return intentMatch[1].trim().split(/\r?\n/)[0];
|
|
170
|
+
const firstPara = wf.overview.split(/\r?\n/).find(l => l.trim() !== '' && !l.startsWith('#'));
|
|
171
|
+
return firstPara ? firstPara.trim() : '';
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.WorkflowParser = WorkflowParser;
|
package/index.js
CHANGED