fraim 2.0.177 → 2.0.180
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/desktop-main.js +2 -2
- package/dist/src/ai-hub/server.js +50 -1
- package/dist/src/api/admin/payments.js +33 -0
- package/dist/src/api/admin/sales-leads.js +21 -0
- package/dist/src/api/payment/create-session.js +338 -0
- package/dist/src/api/payment/dashboard-link.js +149 -0
- package/dist/src/api/payment/session-details.js +31 -0
- package/dist/src/api/payment/webhook.js +587 -0
- package/dist/src/api/personas/me.js +29 -0
- package/dist/src/api/pricing/get-config.js +25 -0
- package/dist/src/api/sales/contact.js +44 -0
- package/dist/src/cli/commands/add-provider.js +74 -61
- package/dist/src/cli/commands/add-surface.js +128 -0
- package/dist/src/cli/commands/login.js +5 -69
- package/dist/src/cli/commands/setup.js +27 -347
- package/dist/src/cli/distribution/marketplace-bundles.js +580 -0
- package/dist/src/cli/fraim.js +2 -0
- package/dist/src/cli/mcp/ide-formats.js +5 -3
- package/dist/src/cli/mcp/mcp-server-registry.js +10 -3
- package/dist/src/cli/providers/local-provider-registry.js +2 -3
- package/dist/src/cli/setup/auto-mcp-setup.js +9 -32
- package/dist/src/cli/setup/ide-detector.js +34 -14
- package/dist/src/config/persona-capability-bundles.js +17 -13
- package/dist/src/db/payment-repository.js +61 -0
- package/dist/src/first-run/session-service.js +2 -2
- package/dist/src/fraim/config-loader.js +11 -0
- package/dist/src/fraim/db-service.js +2387 -0
- package/dist/src/fraim/issues.js +152 -0
- package/dist/src/fraim/template-processor.js +184 -0
- package/dist/src/fraim/utils/request-utils.js +23 -0
- package/dist/src/local-mcp-server/stdio-server.js +28 -4
- package/dist/src/local-mcp-server/usage-collector.js +24 -0
- package/dist/src/middleware/auth.js +266 -0
- package/dist/src/middleware/cors-config.js +111 -0
- package/dist/src/middleware/logger.js +116 -0
- package/dist/src/middleware/rate-limit.js +110 -0
- package/dist/src/middleware/reject-query-api-key.js +45 -0
- package/dist/src/middleware/security-headers.js +41 -0
- package/dist/src/middleware/telemetry.js +134 -0
- package/dist/src/models/payment.js +2 -0
- package/dist/src/routes/analytics.js +1447 -0
- package/dist/src/routes/app-routes.js +32 -0
- package/dist/src/routes/auth-routes.js +505 -0
- package/dist/src/routes/oauth-routes.js +325 -0
- package/dist/src/routes/payment-routes.js +186 -0
- package/dist/src/routes/persona-catalog-routes.js +84 -0
- package/dist/src/services/admin-service.js +229 -0
- package/dist/src/services/audit-log-persistence.js +60 -0
- package/dist/src/services/audit-log.js +69 -0
- package/dist/src/services/cookie-service.js +129 -0
- package/dist/src/services/dashboard-access.js +27 -0
- package/dist/src/services/demo-seed-service.js +139 -0
- package/dist/src/services/email-code.js +23 -0
- package/dist/src/services/email-service-clean.js +782 -0
- package/dist/src/services/email-service.js +951 -0
- package/dist/src/services/installer-service.js +131 -0
- package/dist/src/services/mcp-oauth-store.js +33 -0
- package/dist/src/services/mcp-service.js +823 -0
- package/dist/src/services/oauth-helpers.js +127 -0
- package/dist/src/services/org-service.js +89 -0
- package/dist/src/services/persona-entitlement-service.js +288 -0
- package/dist/src/services/provider-service.js +215 -0
- package/dist/src/services/registry-service.js +628 -0
- package/dist/src/services/session-service.js +86 -0
- package/dist/src/services/trial-reminder-service.js +120 -0
- package/dist/src/services/usage-analytics-service.js +419 -0
- package/dist/src/services/workspace-identity.js +21 -0
- package/dist/src/types/analytics.js +2 -0
- package/dist/src/utils/payment-calculator.js +52 -0
- package/extensions/office-word/favicon.ico +0 -0
- package/extensions/office-word/icon-64.png +0 -0
- package/extensions/office-word/manifest.xml +33 -0
- package/extensions/office-word/taskpane.html +242 -0
- package/package.json +14 -3
- package/public/ai-hub/index.html +14 -2
- package/public/ai-hub/script.js +340 -66
- package/public/ai-hub/styles.css +83 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculatePaymentAmount = calculatePaymentAmount;
|
|
4
|
+
exports.calculateDiscount = calculateDiscount;
|
|
5
|
+
exports.validateFounderEmail = validateFounderEmail;
|
|
6
|
+
exports.isConsumerEmailDomain = isConsumerEmailDomain;
|
|
7
|
+
const pricing_1 = require("../config/pricing");
|
|
8
|
+
function calculatePaymentAmount(plan, numberOfUsers, billingCycle, founderDiscount) {
|
|
9
|
+
let baseAmount;
|
|
10
|
+
if (plan === 'managed') {
|
|
11
|
+
// Managed plan: $200/user/month (license) + $10K per group of 10 (training/support)
|
|
12
|
+
const licenseCost = pricing_1.PRICING[plan][billingCycle] * numberOfUsers;
|
|
13
|
+
const numberOfGroups = Math.ceil(numberOfUsers / pricing_1.MANAGED_PRICING.licensesPerGroup);
|
|
14
|
+
const trainingCost = numberOfGroups * pricing_1.MANAGED_PRICING[billingCycle];
|
|
15
|
+
baseAmount = licenseCost + trainingCost;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Self-served plan: per-user pricing
|
|
19
|
+
const userCost = pricing_1.PRICING[plan][billingCycle] * numberOfUsers;
|
|
20
|
+
const fixedFee = pricing_1.FIXED_FEES[plan];
|
|
21
|
+
baseAmount = userCost + fixedFee;
|
|
22
|
+
}
|
|
23
|
+
if (founderDiscount) {
|
|
24
|
+
const discountAmount = Math.round(baseAmount * pricing_1.FOUNDER_DISCOUNT_RATE);
|
|
25
|
+
const amount = baseAmount - discountAmount;
|
|
26
|
+
return { amount, discountAmount };
|
|
27
|
+
}
|
|
28
|
+
return { amount: baseAmount, discountAmount: 0 };
|
|
29
|
+
}
|
|
30
|
+
function calculateDiscount(amount) {
|
|
31
|
+
return Math.round(amount * pricing_1.FOUNDER_DISCOUNT_RATE);
|
|
32
|
+
}
|
|
33
|
+
function validateFounderEmail(email) {
|
|
34
|
+
if (!email || !email.includes('@')) {
|
|
35
|
+
return { valid: false, reason: 'Invalid email format' };
|
|
36
|
+
}
|
|
37
|
+
const parts = email.split('@');
|
|
38
|
+
if (parts.length !== 2 || !parts[1] || parts[1].trim() === '') {
|
|
39
|
+
return { valid: false, reason: 'Invalid email format' };
|
|
40
|
+
}
|
|
41
|
+
const domain = parts[1].toLowerCase();
|
|
42
|
+
if (isConsumerEmailDomain(domain)) {
|
|
43
|
+
return {
|
|
44
|
+
valid: false,
|
|
45
|
+
reason: 'Founder/Academia discount requires a company or university email address (not gmail, yahoo, etc.)'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { valid: true };
|
|
49
|
+
}
|
|
50
|
+
function isConsumerEmailDomain(domain) {
|
|
51
|
+
return pricing_1.CONSUMER_EMAIL_DOMAINS.includes(domain.toLowerCase());
|
|
52
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
|
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
4
|
+
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
|
|
5
|
+
xsi:type="TaskPaneApp">
|
|
6
|
+
<Id>d1090951-50cf-4cf2-9d12-b0f8541d265c</Id>
|
|
7
|
+
<Version>1.0.0.0</Version>
|
|
8
|
+
<ProviderName>FRAIM</ProviderName>
|
|
9
|
+
<DefaultLocale>en-US</DefaultLocale>
|
|
10
|
+
<DisplayName DefaultValue="FRAIM"/>
|
|
11
|
+
<Description DefaultValue="AI Hub for your document - legal, product, engineering, and more in one task pane."/>
|
|
12
|
+
<IconUrl DefaultValue="http://localhost:43091/word-taskpane/icon-64.png"/>
|
|
13
|
+
<HighResolutionIconUrl DefaultValue="http://localhost:43091/word-taskpane/icon-64.png"/>
|
|
14
|
+
<AppDomains>
|
|
15
|
+
<AppDomain>https://appsforoffice.microsoft.com</AppDomain>
|
|
16
|
+
</AppDomains>
|
|
17
|
+
|
|
18
|
+
<Hosts>
|
|
19
|
+
<Host Name="Document"/>
|
|
20
|
+
</Hosts>
|
|
21
|
+
|
|
22
|
+
<Requirements>
|
|
23
|
+
<Sets>
|
|
24
|
+
<Set Name="WordApi" MinVersion="1.1"/>
|
|
25
|
+
</Sets>
|
|
26
|
+
</Requirements>
|
|
27
|
+
|
|
28
|
+
<DefaultSettings>
|
|
29
|
+
<SourceLocation DefaultValue="http://localhost:43091/word-taskpane/"/>
|
|
30
|
+
</DefaultSettings>
|
|
31
|
+
|
|
32
|
+
<Permissions>ReadWriteDocument</Permissions>
|
|
33
|
+
</OfficeApp>
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>FRAIM Hub</title>
|
|
7
|
+
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>
|
|
8
|
+
<script src="config.js" type="text/javascript"></script>
|
|
9
|
+
<style>
|
|
10
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
11
|
+
html, body { height: 100%; overflow: hidden; }
|
|
12
|
+
iframe { width: 100%; height: 100vh; border: none; display: block; }
|
|
13
|
+
</style>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<iframe id="hub" src="" allow="clipboard-read; clipboard-write"></iframe>
|
|
17
|
+
<script>
|
|
18
|
+
// In Word Online the taskpane is served over HTTPS (ssl-proxy at localhost:43092).
|
|
19
|
+
// Loading an HTTP iframe from an HTTPS page is mixed-content-blocked, so use the
|
|
20
|
+
// same origin as the taskpane when running over HTTPS (the ssl-proxy forwards all
|
|
21
|
+
// routes to the Hub). HTTP (isolated tests) keeps the direct Hub address.
|
|
22
|
+
var HUB_ORIGIN = window.location.protocol === 'https:'
|
|
23
|
+
? window.location.origin
|
|
24
|
+
: (window.FRAIM_HUB_ORIGIN || 'http://127.0.0.1:43091');
|
|
25
|
+
var hubFrame = document.getElementById('hub');
|
|
26
|
+
var pendingPush = null; // context queued before hub-ready fires
|
|
27
|
+
var hubReady = false;
|
|
28
|
+
var selectionHandlerAdded = false;
|
|
29
|
+
|
|
30
|
+
// ── postMessage bridge (inbound from Hub) ─────────────────────────────────
|
|
31
|
+
window.addEventListener('message', function(event) {
|
|
32
|
+
if (event.origin !== HUB_ORIGIN) return;
|
|
33
|
+
var msg = event.data || {};
|
|
34
|
+
if (msg.type === 'hub-ready') {
|
|
35
|
+
hubReady = true;
|
|
36
|
+
if (pendingPush) { pushToHub(pendingPush); pendingPush = null; }
|
|
37
|
+
} else if (msg.type === 'word-request') {
|
|
38
|
+
handleWordRequest(msg.action, msg.requestId, msg.payload || {});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function pushToHub(msg) {
|
|
43
|
+
if (hubFrame && hubFrame.contentWindow) {
|
|
44
|
+
hubFrame.contentWindow.postMessage(msg, HUB_ORIGIN);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Reading Word context ───────────────────────────────────────────────────
|
|
49
|
+
function docMeta() {
|
|
50
|
+
var meta = { docUrl: '', docTitle: '' };
|
|
51
|
+
try {
|
|
52
|
+
var doc = window.Office && Office.context && Office.context.document;
|
|
53
|
+
meta.docUrl = (doc && doc.url) ? doc.url : '';
|
|
54
|
+
if (meta.docUrl) {
|
|
55
|
+
var parts = meta.docUrl.replace(/\\/g, '/').split('/');
|
|
56
|
+
meta.docTitle = (parts[parts.length - 1] || '').replace(/\.[^.]+$/, '');
|
|
57
|
+
}
|
|
58
|
+
} catch(e) {}
|
|
59
|
+
return meta;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function readSelectionAsync(cb) {
|
|
63
|
+
try {
|
|
64
|
+
Office.context.document.getSelectedDataAsync(
|
|
65
|
+
Office.CoercionType.Text,
|
|
66
|
+
{ valueFormat: 'unformatted', filterType: 'onlySelected' },
|
|
67
|
+
function(r) { cb(r.status === Office.AsyncResultStatus.Succeeded ? String(r.value || '').trim() : ''); }
|
|
68
|
+
);
|
|
69
|
+
} catch(e) { cb(''); }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function readBodyAsync(cb) {
|
|
73
|
+
try {
|
|
74
|
+
Office.context.document.getSelectedDataAsync(
|
|
75
|
+
Office.CoercionType.Text,
|
|
76
|
+
{ valueFormat: 'unformatted' },
|
|
77
|
+
function(r) { cb(r.status === Office.AsyncResultStatus.Succeeded ? String(r.value || '') : ''); }
|
|
78
|
+
);
|
|
79
|
+
} catch(e) { cb(''); }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readCommentsAsync(cb) {
|
|
83
|
+
try {
|
|
84
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
85
|
+
Word.run(function(ctx) {
|
|
86
|
+
var comments = ctx.document.body.getComments();
|
|
87
|
+
comments.load('items/id,items/authorName,items/content,items/resolved');
|
|
88
|
+
return ctx.sync().then(function() {
|
|
89
|
+
cb((comments.items || []).slice(0, 20).map(function(c) {
|
|
90
|
+
return { id: c.id || '', author: c.authorName || '', text: c.content || '', resolved: !!c.resolved };
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
}).catch(function() { cb([]); });
|
|
94
|
+
} else { cb([]); }
|
|
95
|
+
} catch(e) { cb([]); }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readFullContext(cb) {
|
|
99
|
+
var meta = docMeta();
|
|
100
|
+
readSelectionAsync(function(selection) {
|
|
101
|
+
readBodyAsync(function(body) {
|
|
102
|
+
readCommentsAsync(function(comments) {
|
|
103
|
+
cb({
|
|
104
|
+
docUrl: meta.docUrl,
|
|
105
|
+
docTitle: meta.docTitle,
|
|
106
|
+
selection: selection,
|
|
107
|
+
hasSelection: selection.length > 0,
|
|
108
|
+
bodyPreview: body.slice(0, 2000),
|
|
109
|
+
wordCount: body ? body.split(/\s+/).filter(Boolean).length : 0,
|
|
110
|
+
comments: comments,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Selection-change handler ───────────────────────────────────────────────
|
|
118
|
+
function addSelectionHandler() {
|
|
119
|
+
if (selectionHandlerAdded) return;
|
|
120
|
+
try {
|
|
121
|
+
Office.context.document.addHandlerAsync(
|
|
122
|
+
Office.EventType.DocumentSelectionChanged,
|
|
123
|
+
function() {
|
|
124
|
+
readSelectionAsync(function(sel) {
|
|
125
|
+
var m = docMeta();
|
|
126
|
+
pushToHub({ type: 'word-context-update', payload: {
|
|
127
|
+
docUrl: m.docUrl, docTitle: m.docTitle,
|
|
128
|
+
selection: sel, hasSelection: sel.length > 0,
|
|
129
|
+
}});
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
function(r) { if (r.status === Office.AsyncResultStatus.Succeeded) selectionHandlerAdded = true; }
|
|
133
|
+
);
|
|
134
|
+
} catch(e) {}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Handling requests from Hub ─────────────────────────────────────────────
|
|
138
|
+
function handleWordRequest(action, requestId, payload) {
|
|
139
|
+
function respond(result) {
|
|
140
|
+
pushToHub({ type: 'word-response', requestId: requestId, payload: result });
|
|
141
|
+
}
|
|
142
|
+
if (action === 'get-context') {
|
|
143
|
+
readFullContext(function(ctx) { respond(ctx); });
|
|
144
|
+
} else if (action === 'get-selection') {
|
|
145
|
+
readSelectionAsync(function(sel) { respond({ selection: sel, hasSelection: sel.length > 0 }); });
|
|
146
|
+
} else if (action === 'insert-text') {
|
|
147
|
+
// Replace current selection (or insert at cursor) with given text.
|
|
148
|
+
try {
|
|
149
|
+
Office.context.document.setSelectedDataAsync(
|
|
150
|
+
payload.text || '',
|
|
151
|
+
{ coercionType: Office.CoercionType.Text },
|
|
152
|
+
function(r) { respond({ ok: r.status === Office.AsyncResultStatus.Succeeded }); }
|
|
153
|
+
);
|
|
154
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
155
|
+
} else if (action === 'insert-after') {
|
|
156
|
+
// Insert text after the current selection using Word API.
|
|
157
|
+
try {
|
|
158
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
159
|
+
Word.run(function(ctx) {
|
|
160
|
+
var sel = ctx.document.getSelection();
|
|
161
|
+
sel.insertText((payload.newline !== false ? '\n' : '') + (payload.text || ''), Word.InsertLocation.after);
|
|
162
|
+
return ctx.sync();
|
|
163
|
+
}).then(function() { respond({ ok: true }); }).catch(function(e) { respond({ ok: false, error: e.message }); });
|
|
164
|
+
} else { respond({ ok: false, error: 'Word API 1.1+ not available' }); }
|
|
165
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
166
|
+
} else if (action === 'append-to-doc') {
|
|
167
|
+
// Append text at the very end of the document.
|
|
168
|
+
try {
|
|
169
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
170
|
+
Word.run(function(ctx) {
|
|
171
|
+
ctx.document.body.insertText('\n' + (payload.text || ''), Word.InsertLocation.end);
|
|
172
|
+
return ctx.sync();
|
|
173
|
+
}).then(function() { respond({ ok: true }); }).catch(function(e) { respond({ ok: false, error: e.message }); });
|
|
174
|
+
} else { respond({ ok: false, error: 'Word API 1.1+ not available' }); }
|
|
175
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
176
|
+
} else if (action === 'reply-to-comment') {
|
|
177
|
+
// Reply to a comment by ID.
|
|
178
|
+
try {
|
|
179
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
180
|
+
Word.run(function(ctx) {
|
|
181
|
+
var comments = ctx.document.body.getComments();
|
|
182
|
+
comments.load('items/id');
|
|
183
|
+
return ctx.sync().then(function() {
|
|
184
|
+
var target = (comments.items || []).find(function(c) { return c.id === payload.commentId; });
|
|
185
|
+
if (!target) throw new Error('Comment not found: ' + payload.commentId);
|
|
186
|
+
target.reply(payload.text || '');
|
|
187
|
+
return ctx.sync();
|
|
188
|
+
});
|
|
189
|
+
}).then(function() { respond({ ok: true }); }).catch(function(e) { respond({ ok: false, error: e.message }); });
|
|
190
|
+
} else { respond({ ok: false, error: 'Word API not available' }); }
|
|
191
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
192
|
+
} else if (action === 'track-changes-on') {
|
|
193
|
+
try {
|
|
194
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
195
|
+
Word.run(function(ctx) {
|
|
196
|
+
ctx.document.changeTrackingMode = Word.ChangeTrackingMode.trackAll;
|
|
197
|
+
return ctx.sync();
|
|
198
|
+
}).then(function() { respond({ ok: true }); }).catch(function(e) { respond({ ok: false, error: e.message }); });
|
|
199
|
+
} else { respond({ ok: false, error: 'Word API not available' }); }
|
|
200
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
201
|
+
} else if (action === 'track-changes-off') {
|
|
202
|
+
try {
|
|
203
|
+
if (typeof Word !== 'undefined' && Word.run) {
|
|
204
|
+
Word.run(function(ctx) {
|
|
205
|
+
ctx.document.changeTrackingMode = Word.ChangeTrackingMode.off;
|
|
206
|
+
return ctx.sync();
|
|
207
|
+
}).then(function() { respond({ ok: true }); }).catch(function(e) { respond({ ok: false, error: e.message }); });
|
|
208
|
+
} else { respond({ ok: false, error: 'Word API not available' }); }
|
|
209
|
+
} catch(e) { respond({ ok: false, error: e.message }); }
|
|
210
|
+
} else {
|
|
211
|
+
respond({ ok: false, error: 'Unknown action: ' + action });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ── Mount ─────────────────────────────────────────────────────────────────
|
|
216
|
+
function mountHub() {
|
|
217
|
+
var meta = docMeta();
|
|
218
|
+
var params = new URLSearchParams({ surface: 'task-pane' });
|
|
219
|
+
if (meta.docUrl) params.set('docUrl', meta.docUrl);
|
|
220
|
+
if (meta.docTitle) params.set('docTitle', meta.docTitle);
|
|
221
|
+
hubFrame.src = HUB_ORIGIN + '/ai-hub/?' + params.toString();
|
|
222
|
+
|
|
223
|
+
hubFrame.addEventListener('load', function() {
|
|
224
|
+
// Push full context once Hub has registered its message listener.
|
|
225
|
+
setTimeout(function() {
|
|
226
|
+
readFullContext(function(ctx) {
|
|
227
|
+
var msg = { type: 'word-context', payload: ctx };
|
|
228
|
+
if (hubReady) { pushToHub(msg); } else { pendingPush = msg; }
|
|
229
|
+
});
|
|
230
|
+
}, 300);
|
|
231
|
+
addSelectionHandler();
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (typeof Office !== 'undefined') {
|
|
236
|
+
Office.onReady(function() { mountHub(); });
|
|
237
|
+
} else {
|
|
238
|
+
window.addEventListener('DOMContentLoaded', mountHub);
|
|
239
|
+
}
|
|
240
|
+
</script>
|
|
241
|
+
</body>
|
|
242
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.180",
|
|
4
4
|
"description": "FRAIM CLI - Framework for Rigor-based AI Management (alias for fraim-framework)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"dev": "tsx --watch src/fraim-mcp-server.ts > server.log 2>&1",
|
|
11
11
|
"dev:prod": "npm run build && node dist/src/fraim-mcp-server.js > server.log 2>&1",
|
|
12
|
-
"build": "tsx scripts/build-fraim-config-schema-template.ts && npm run typecheck:scripts && tsc && npm run build:stubs && npm run build:fraim-brain && node scripts/copy-registry.js && npm run validate:registry && npm run validate:fraim-pro-assets && npm run validate:employee-catalog && npm run validate:learning-format-contract && tsx scripts/validate-purity.ts",
|
|
12
|
+
"build": "tsx scripts/build-fraim-config-schema-template.ts && npm run typecheck:scripts && tsc && npm run build:stubs && npm run build:fraim-brain && node scripts/copy-registry.js && npm run validate:registry && npm run validate:marketplaces && npm run validate:fraim-pro-assets && npm run validate:employee-catalog && npm run validate:learning-format-contract && tsx scripts/validate-purity.ts",
|
|
13
13
|
"validate:learning-format-contract": "tsx scripts/validate-learning-format-contract.ts",
|
|
14
14
|
"build:stubs": "tsx scripts/build-stub-registry.ts",
|
|
15
15
|
"build:fraim-brain": "node scripts/generate-fraim-brain.js",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"publish-fraim-only": "node scripts/publish-fraim.js",
|
|
51
51
|
"publish-both-manual": "node scripts/publish-both.js",
|
|
52
52
|
"validate:registry": "tsx scripts/verify-registry-paths.ts && npm run validate:jobs && npm run validate:skills && npm run validate:registry-references && npm run validate:platform-agnostic && npm run validate:template-namespaces && npm run validate:config-fallbacks && npm run validate:bootstrap-config-coverage && npm run validate:provider-action-mappings && npm run validate:fidelity && npm run validate:config-tokens && npm run validate:brain-mapping && npm run validate:template-syntax",
|
|
53
|
+
"validate:marketplaces": "tsx scripts/validate-marketplace-bundles.ts",
|
|
53
54
|
"typecheck:scripts": "tsc -p tsconfig.scripts.json --pretty false",
|
|
54
55
|
"validate:registry-references": "tsx scripts/validate-registry-references.ts",
|
|
55
56
|
"validate:brain-mapping": "tsx scripts/validate-brain-mapping.ts",
|
|
@@ -111,7 +112,6 @@
|
|
|
111
112
|
"fast-glob": "^3.3.3",
|
|
112
113
|
"markdown-it": "^14.1.1",
|
|
113
114
|
"markdown-it-highlightjs": "^4.3.0",
|
|
114
|
-
"node-cron": "^4.2.1",
|
|
115
115
|
"playwright": "^1.58.2",
|
|
116
116
|
"pptxgenjs": "^4.0.1",
|
|
117
117
|
"promptfoo": "^0.121.17",
|
|
@@ -128,8 +128,18 @@
|
|
|
128
128
|
"dist/src/first-run/",
|
|
129
129
|
"dist/src/core/",
|
|
130
130
|
"dist/src/config/",
|
|
131
|
+
"dist/src/fraim/",
|
|
132
|
+
"dist/src/db/",
|
|
133
|
+
"dist/src/routes/",
|
|
134
|
+
"dist/src/services/",
|
|
135
|
+
"dist/src/api/",
|
|
136
|
+
"dist/src/middleware/",
|
|
137
|
+
"dist/src/models/",
|
|
138
|
+
"dist/src/types/",
|
|
139
|
+
"dist/src/utils/",
|
|
131
140
|
"bin/fraim.js",
|
|
132
141
|
"bin/fraim-mcp.js",
|
|
142
|
+
"extensions/office-word/",
|
|
133
143
|
"public/ai-hub/",
|
|
134
144
|
"public/first-run/",
|
|
135
145
|
"public/portfolio/",
|
|
@@ -156,6 +166,7 @@
|
|
|
156
166
|
"electron": "^41.2.2",
|
|
157
167
|
"express": "^5.2.1",
|
|
158
168
|
"mongodb": "^7.0.0",
|
|
169
|
+
"node-cron": "4.2.1",
|
|
159
170
|
"node-edge-tts": "^1.2.10",
|
|
160
171
|
"nodemailer": "^8.0.3",
|
|
161
172
|
"prompts": "^2.4.2",
|
package/public/ai-hub/index.html
CHANGED
|
@@ -144,8 +144,20 @@
|
|
|
144
144
|
<!-- Overview sub-view: dashboard project cards -->
|
|
145
145
|
<div id="proj-overview">
|
|
146
146
|
<div class="hub-area-page">
|
|
147
|
-
|
|
148
|
-
<div class="
|
|
147
|
+
<!-- Issue #671: Cards / Kanban view toggle -->
|
|
148
|
+
<div class="kb-view-toggle" id="kb-view-toggle">
|
|
149
|
+
<button class="kb-vtab on" data-view="cards" type="button">Cards</button>
|
|
150
|
+
<button class="kb-vtab" data-view="kanban" type="button">Kanban</button>
|
|
151
|
+
</div>
|
|
152
|
+
<div id="proj-cards-view">
|
|
153
|
+
<div class="sec-label" id="proj-cards-label">All projects</div>
|
|
154
|
+
<div class="proj-grid" id="proj-grid"></div>
|
|
155
|
+
<div id="kb-runs-grid" hidden></div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
<!-- Issue #671: Kanban board — rendered by tfRenderKanban() -->
|
|
159
|
+
<div id="proj-kanban" hidden>
|
|
160
|
+
<div id="kb-stats" class="kb-stats"></div>
|
|
149
161
|
</div>
|
|
150
162
|
</div>
|
|
151
163
|
|