@kolbo/mcp 1.87.11 → 1.87.12
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 +1 -1
- package/src/apps/index.js +6 -5
- package/src/apps/theme.js +444 -446
- package/src/apps/widgets/plans.js +164 -113
|
@@ -1,113 +1,164 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { widgetPage } = require('../html');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Plans / upgrade widget — shown by `show_plans`, and by any generation the
|
|
7
|
-
* server refused for credits.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* }
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<span class="k-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
var
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
function
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { widgetPage } = require('../html');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Plans / upgrade widget — shown by `show_plans`, and by any generation the
|
|
7
|
+
* server refused for credits.
|
|
8
|
+
*
|
|
9
|
+
* Rendered NATIVELY from structuredContent. It used to iframe
|
|
10
|
+
* app.kolbo.ai/pricing/embed, which needs `frameDomains` in the widget CSP —
|
|
11
|
+
* OpenAI rejected the ChatGPT app for exactly that on 2026-09-06 ("frameDomains
|
|
12
|
+
* is reserved for limited cases where embedding a third-party experience is
|
|
13
|
+
* essential"). Prices here are the live, promo-adjusted numbers the server
|
|
14
|
+
* fetched from /v1/account/plans at call time; Buy/Subscribe open
|
|
15
|
+
* https://app.kolbo.ai/pricing in a new tab — Stripe and the user's session
|
|
16
|
+
* never run inside a host iframe.
|
|
17
|
+
*
|
|
18
|
+
* structuredContent contract:
|
|
19
|
+
* {
|
|
20
|
+
* widget: 'plans',
|
|
21
|
+
* reason: 'insufficient_credits' | 'requested',
|
|
22
|
+
* balance, required, shortfall, // when reason === 'insufficient_credits'
|
|
23
|
+
* current_plan: { key, name },
|
|
24
|
+
* plans: [{ key, name, interval, credits, price, original_price,
|
|
25
|
+
* discount_percent, promo_text, currency, top_up_discount }],
|
|
26
|
+
* credit_packs: [{ …, subscriber_price, is_subscriber }],
|
|
27
|
+
* pricing_url
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const BODY = `
|
|
32
|
+
<div class="k-card" id="card">
|
|
33
|
+
<div class="k-head">
|
|
34
|
+
<span class="k-logo" id="logo"></span>
|
|
35
|
+
<span class="k-title" id="tool-title">Plans</span>
|
|
36
|
+
<span class="k-spacer"></span>
|
|
37
|
+
<span class="k-chip" id="balance-chip" style="display:none"></span>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="k-body">
|
|
40
|
+
<div class="k-error" id="notice" style="display:none"></div>
|
|
41
|
+
<div id="stage"></div>
|
|
42
|
+
<div class="k-actions" id="actions"></div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="k-footer">
|
|
45
|
+
<span>Powered by <a href="#" id="kolbo-link">Kolbo.AI</a></span>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const SCRIPT = `
|
|
51
|
+
var state = null;
|
|
52
|
+
var interval = 'month';
|
|
53
|
+
|
|
54
|
+
el('logo').innerHTML = KOLBO_LOGO + '<span>Kolbo</span>';
|
|
55
|
+
el('kolbo-link').onclick = function (e) { e.preventDefault(); window.kolbo.openLink('https://app.kolbo.ai'); };
|
|
56
|
+
|
|
57
|
+
function pricingUrl() {
|
|
58
|
+
return (state && state.pricing_url) || 'https://app.kolbo.ai/pricing';
|
|
59
|
+
}
|
|
60
|
+
function money(v, currency) {
|
|
61
|
+
if (v == null || isNaN(v)) return '';
|
|
62
|
+
var sym = { usd: '$', eur: '\u20ac', gbp: '\u00a3', ils: '\u20aa' }[String(currency || 'usd').toLowerCase()] || '';
|
|
63
|
+
var n = Number(v);
|
|
64
|
+
return sym + (Math.round(n) === n ? String(n) : n.toFixed(2));
|
|
65
|
+
}
|
|
66
|
+
function fmtCredits(n) { return n == null ? '' : Number(n).toLocaleString('en-US'); }
|
|
67
|
+
function isAnnual(p) { return /^(year|annual|yearly)/i.test(String(p.interval || '')); }
|
|
68
|
+
|
|
69
|
+
function planCard(p, opts) {
|
|
70
|
+
var current = state.current_plan && ((state.current_plan.key && state.current_plan.key === p.key) || (state.current_plan.name && state.current_plan.name === p.name));
|
|
71
|
+
var pricing = '<div class="k-plan-pricing"><span class="k-plan-price">' + esc(money(p.price, p.currency)) + '</span>' +
|
|
72
|
+
(p.original_price != null && p.original_price !== p.price ? '<span class="k-plan-was">' + esc(money(p.original_price, p.currency)) + '</span>' : '') +
|
|
73
|
+
(opts.pack ? '' : '<span class="k-plan-note">/ ' + (isAnnual(p) ? 'year' : 'month') + '</span>') + '</div>';
|
|
74
|
+
var badge = current ? '<span class="k-plan-badge current">Current plan</span>'
|
|
75
|
+
: (p.discount_percent ? '<span class="k-plan-badge">' + esc(String(p.discount_percent)) + '% off</span>' : '');
|
|
76
|
+
var note = p.promo_text ? '<div class="k-plan-note">' + esc(p.promo_text) + '</div>'
|
|
77
|
+
: (opts.pack && p.is_subscriber && p.subscriber_price != null ? '<div class="k-plan-note">Subscriber price applied</div>' : '')
|
|
78
|
+
+ (!opts.pack && p.top_up_discount ? '<div class="k-plan-note">Cheaper credit packs included</div>' : '');
|
|
79
|
+
var cta = current ? '' : '<button class="k-btn ' + (opts.pack ? 'ghost' : 'primary') + '" data-open="1">' + (opts.pack ? 'Buy pack' : 'Upgrade') + ' ' + ICONS.open + '</button>';
|
|
80
|
+
return '<div class="k-plan' + (current ? ' current' : '') + '">' +
|
|
81
|
+
'<div class="k-plan-top"><span class="k-plan-name">' + esc(p.name || p.key || 'Plan') + '</span>' + badge + '</div>' +
|
|
82
|
+
(p.credits != null ? '<div class="k-plan-credits">' + ICONS.sparkle + ' ' + esc(fmtCredits(p.credits)) + ' credits' + (opts.pack ? '' : ' / ' + (isAnnual(p) ? 'year' : 'month')) + '</div>' : '') +
|
|
83
|
+
pricing + note + cta + '</div>';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function renderStage() {
|
|
87
|
+
var plans = (state.plans || []).filter(function (p) { return p && (p.price != null || p.credits != null); });
|
|
88
|
+
var packs = (state.credit_packs || []).filter(function (p) { return p && p.price != null; });
|
|
89
|
+
var monthly = plans.filter(function (p) { return !isAnnual(p); });
|
|
90
|
+
var annual = plans.filter(isAnnual);
|
|
91
|
+
var hasToggle = monthly.length && annual.length;
|
|
92
|
+
var shown = hasToggle ? (interval === 'year' ? annual : monthly) : plans;
|
|
93
|
+
var html = '';
|
|
94
|
+
if (hasToggle) {
|
|
95
|
+
html += '<div class="k-plan-toggle">' +
|
|
96
|
+
'<button class="k-toggle-btn' + (interval === 'month' ? ' active' : '') + '" data-interval="month">Monthly</button>' +
|
|
97
|
+
'<button class="k-toggle-btn' + (interval === 'year' ? ' active' : '') + '" data-interval="year">Annual</button></div>';
|
|
98
|
+
}
|
|
99
|
+
if (shown.length) html += '<div class="k-plan-grid">' + shown.map(function (p) { return planCard(p, {}); }).join('') + '</div>';
|
|
100
|
+
if (packs.length) {
|
|
101
|
+
html += '<div class="k-pack-head">Credit packs</div><div class="k-plan-grid">' +
|
|
102
|
+
packs.map(function (p) { return planCard(p, { pack: true }); }).join('') + '</div>';
|
|
103
|
+
}
|
|
104
|
+
if (!html) html = '<div class="k-plan-note">Live plans and prices are on the Kolbo pricing page.</div>';
|
|
105
|
+
el('stage').innerHTML = html;
|
|
106
|
+
var btns = el('stage').querySelectorAll('[data-interval]');
|
|
107
|
+
for (var i = 0; i < btns.length; i++) btns[i].onclick = function () { interval = this.getAttribute('data-interval'); renderStage(); window.kolbo.notifySize(); };
|
|
108
|
+
var opens = el('stage').querySelectorAll('[data-open]');
|
|
109
|
+
for (var j = 0; j < opens.length; j++) opens[j].onclick = function () { window.kolbo.openLink(pricingUrl()); };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function boot(sc) {
|
|
113
|
+
if (!sc) return;
|
|
114
|
+
state = sc;
|
|
115
|
+
el('tool-title').textContent = sc.reason === 'insufficient_credits' ? 'Out of credits' : 'Plans';
|
|
116
|
+
|
|
117
|
+
if (sc.balance != null) {
|
|
118
|
+
var chip = el('balance-chip');
|
|
119
|
+
chip.style.display = '';
|
|
120
|
+
chip.innerHTML = ICONS.sparkle + ' ' + esc(String(sc.balance)) + ' credits left';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (sc.reason === 'insufficient_credits') {
|
|
124
|
+
var need = sc.shortfall != null ? sc.shortfall
|
|
125
|
+
: (sc.required != null && sc.balance != null ? Math.max(0, sc.required - sc.balance) : null);
|
|
126
|
+
el('notice').style.display = '';
|
|
127
|
+
el('notice').innerHTML = ICONS.warn + ' ' +
|
|
128
|
+
esc(need ? ('That generation needs ' + need + ' more credit' + (need === 1 ? '' : 's') + '.')
|
|
129
|
+
: 'That generation needs more credits than you have left.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
renderStage();
|
|
133
|
+
renderActions();
|
|
134
|
+
window.kolbo.notifySize();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function renderActions() {
|
|
138
|
+
el('actions').innerHTML =
|
|
139
|
+
'<button class="k-btn ghost" id="btn-pricing">See all plans ' + ICONS.open + '</button>';
|
|
140
|
+
el('btn-pricing').onclick = function () { window.kolbo.openLink(pricingUrl()); };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
window.kolbo.onToolResult(function (result) {
|
|
144
|
+
var sc = result.structuredContent || structured(result);
|
|
145
|
+
if (sc) boot(sc);
|
|
146
|
+
});
|
|
147
|
+
window.kolbo.onToolInput(function () {
|
|
148
|
+
if (state) return;
|
|
149
|
+
el('stage').innerHTML = '<div class="k-skel square" style="min-height:240px"></div>';
|
|
150
|
+
window.kolbo.notifySize();
|
|
151
|
+
});
|
|
152
|
+
window.kolbo.ready(function (ctx) {
|
|
153
|
+
var info = ctx && ctx.toolInfo;
|
|
154
|
+
if (state || !info) return;
|
|
155
|
+
var raw = info.result && (info.result.structuredContent || structured(info.result));
|
|
156
|
+
if (raw) boot(raw);
|
|
157
|
+
});
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
function plansWidgetHtml() {
|
|
161
|
+
return widgetPage({ title: 'Kolbo Plans', body: BODY, script: SCRIPT });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { plansWidgetHtml };
|