ft-scout 8.0.9 → 9.0.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["pricing.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,CAAC;AACrD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CA0DtE,CAAC;AAQF,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAoBtE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAoCtH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAcxG;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAE5E"}
@@ -0,0 +1,143 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const PRICING_DIR = path.join(os.homedir(), '.ft');
5
+ const PRICING_FILE = path.join(PRICING_DIR, 'pricing.json');
6
+ export const DEFAULT_PRICING_CONFIG = {
7
+ free: {
8
+ id: 'free',
9
+ name: 'Developer Free',
10
+ monthlyPriceINR: 0,
11
+ annualPriceINR: 0,
12
+ monthlyPriceUSD: 0,
13
+ annualPriceUSD: 0,
14
+ credits: 100,
15
+ description: 'Essential tools for individual developer workflow',
16
+ features: [
17
+ '100 AI credits / month',
18
+ 'Full Scout CLI core features',
19
+ '1 Active CLI session slot',
20
+ 'Single-use authorization tokens',
21
+ 'Community support & docs',
22
+ ],
23
+ },
24
+ pro: {
25
+ id: 'pro',
26
+ name: 'Pro Developer',
27
+ monthlyPriceINR: 50, // ₹50 as requested by user
28
+ annualPriceINR: 45,
29
+ monthlyPriceUSD: 0.99,
30
+ annualPriceUSD: 0.79,
31
+ credits: 1000,
32
+ description: 'High-power AI co-pilot capabilities, priority quota & live visual HUD',
33
+ popular: true,
34
+ badge: 'POPULAR',
35
+ features: [
36
+ '1,000 AI credits / month',
37
+ 'Unlimited AI co-pilot queries',
38
+ 'Up to 5 Active CLI Sessions',
39
+ 'Live Screen Sharing & Visual Perception HUD',
40
+ 'Fast-track model response engine',
41
+ 'Priority token revocation & audit logs',
42
+ 'Direct email support response',
43
+ ],
44
+ },
45
+ enterprise: {
46
+ id: 'enterprise',
47
+ name: 'Team & Enterprise',
48
+ monthlyPriceINR: 3999,
49
+ annualPriceINR: 37990,
50
+ monthlyPriceUSD: 49,
51
+ annualPriceUSD: 39,
52
+ credits: 10000,
53
+ description: 'Organization controls, security policies & dedicated scale',
54
+ features: [
55
+ '10,000 AI credits / month',
56
+ 'Multi-seat organization access',
57
+ 'Unlimited CLI Session connections',
58
+ 'Window Isolation & Multi-App Vision Engine',
59
+ 'Custom security token policies',
60
+ 'Dedicated account SLA support',
61
+ '24/7 SLA Priority response',
62
+ ],
63
+ },
64
+ };
65
+ function ensurePricingDir() {
66
+ if (!fs.existsSync(PRICING_DIR)) {
67
+ fs.mkdirSync(PRICING_DIR, { recursive: true });
68
+ }
69
+ }
70
+ export function getPricingConfig() {
71
+ try {
72
+ if (fs.existsSync(PRICING_FILE)) {
73
+ const raw = fs.readFileSync(PRICING_FILE, 'utf-8');
74
+ const parsed = JSON.parse(raw);
75
+ if (parsed && typeof parsed === 'object' && parsed.pro && parsed.free) {
76
+ return {
77
+ free: { ...DEFAULT_PRICING_CONFIG.free, ...parsed.free },
78
+ pro: { ...DEFAULT_PRICING_CONFIG.pro, ...parsed.pro },
79
+ enterprise: { ...DEFAULT_PRICING_CONFIG.enterprise, ...parsed.enterprise },
80
+ };
81
+ }
82
+ }
83
+ }
84
+ catch (err) {
85
+ console.warn('[Pricing Engine] Error reading pricing file, using default configuration:', err);
86
+ }
87
+ // Auto-initialize file if it doesn't exist
88
+ saveFullPricingConfig(DEFAULT_PRICING_CONFIG);
89
+ return { ...DEFAULT_PRICING_CONFIG };
90
+ }
91
+ export function saveFullPricingConfig(config) {
92
+ ensurePricingDir();
93
+ const cleanConfig = {
94
+ free: {
95
+ ...DEFAULT_PRICING_CONFIG.free,
96
+ ...config.free,
97
+ id: 'free',
98
+ monthlyPriceINR: 0,
99
+ annualPriceINR: 0,
100
+ monthlyPriceUSD: 0,
101
+ annualPriceUSD: 0,
102
+ },
103
+ pro: {
104
+ ...DEFAULT_PRICING_CONFIG.pro,
105
+ ...config.pro,
106
+ id: 'pro',
107
+ monthlyPriceINR: Math.max(1, Number(config.pro?.monthlyPriceINR || 50)),
108
+ annualPriceINR: Math.max(1, Number(config.pro?.annualPriceINR || 45)),
109
+ monthlyPriceUSD: Math.max(0.01, Number(config.pro?.monthlyPriceUSD || 0.99)),
110
+ annualPriceUSD: Math.max(0.01, Number(config.pro?.annualPriceUSD || 0.79)),
111
+ credits: Math.max(100, Number(config.pro?.credits || 1000)),
112
+ },
113
+ enterprise: {
114
+ ...DEFAULT_PRICING_CONFIG.enterprise,
115
+ ...config.enterprise,
116
+ id: 'enterprise',
117
+ monthlyPriceINR: Math.max(1, Number(config.enterprise?.monthlyPriceINR || 3999)),
118
+ annualPriceINR: Math.max(1, Number(config.enterprise?.annualPriceINR || 37990)),
119
+ monthlyPriceUSD: Math.max(1, Number(config.enterprise?.monthlyPriceUSD || 49)),
120
+ annualPriceUSD: Math.max(1, Number(config.enterprise?.annualPriceUSD || 39)),
121
+ credits: Math.max(1000, Number(config.enterprise?.credits || 10000)),
122
+ },
123
+ };
124
+ fs.writeFileSync(PRICING_FILE, JSON.stringify(cleanConfig, null, 2), 'utf-8');
125
+ return cleanConfig;
126
+ }
127
+ export function updatePricingTier(tier, updates) {
128
+ const current = getPricingConfig();
129
+ if (!current[tier]) {
130
+ throw new Error(`Invalid plan tier: ${tier}`);
131
+ }
132
+ current[tier] = {
133
+ ...current[tier],
134
+ ...updates,
135
+ id: tier,
136
+ };
137
+ const saved = saveFullPricingConfig(current);
138
+ return saved[tier];
139
+ }
140
+ export function resetPricingToDefaults() {
141
+ return saveFullPricingConfig(DEFAULT_PRICING_CONFIG);
142
+ }
143
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["pricing.ts"],"names":[],"mappings":"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"}
package/firebase.json CHANGED
@@ -25,6 +25,14 @@
25
25
  }
26
26
  ],
27
27
  "rewrites": [
28
+ {
29
+ "source": "/admin",
30
+ "destination": "/admin.html"
31
+ },
32
+ {
33
+ "source": "/admin/**",
34
+ "destination": "/admin.html"
35
+ },
28
36
  {
29
37
  "source": "/auth",
30
38
  "destination": "/authentication.html"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ft-scout",
3
- "version": "8.0.9",
3
+ "version": "9.0.0",
4
4
  "type": "module",
5
5
  "description": "FrontTerrain — The Onboarding Co-Pilot for New Codebases",
6
6
  "main": "index.js",
package/web/app.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* ==========================================================================
2
- FrontTerrain Scout — Multi-Page Application Engine v8.0.9
2
+ FrontTerrain Scout — Multi-Page Application Engine v9.0.0
3
3
  ========================================================================== */
4
4
 
5
5
  const FIREBASE_CONFIG = {
@@ -52,6 +52,11 @@ let state = {
52
52
  customApiKey: '',
53
53
  customBaseUrl: '',
54
54
  razorpayKeyId: '',
55
+ pricing: {
56
+ free: { monthlyPriceINR: 0, annualPriceINR: 0, monthlyPriceUSD: 0, annualPriceUSD: 0, credits: 100 },
57
+ pro: { monthlyPriceINR: 50, annualPriceINR: 45, monthlyPriceUSD: 0.99, annualPriceUSD: 0.79, credits: 1000 },
58
+ enterprise: { monthlyPriceINR: 3999, annualPriceINR: 37990, monthlyPriceUSD: 49, annualPriceUSD: 39, credits: 10000 },
59
+ },
55
60
  };
56
61
 
57
62
  let pendingCheckoutTier = null;
@@ -179,6 +184,49 @@ async function checkPaymentRedirectCallback() {
179
184
  }
180
185
  }
181
186
 
187
+ // Dynamic Pricing Loader & Admin Navigation Hook
188
+ async function loadDynamicPricing() {
189
+ try {
190
+ const res = await fetch('/api/pricing');
191
+ if (res.ok) {
192
+ const data = await res.json();
193
+ if (data && data.success && data.pricing) {
194
+ state.pricing = data.pricing;
195
+ renderTiersUI();
196
+ }
197
+ }
198
+ } catch { }
199
+
200
+ try {
201
+ const adminToken = sessionStorage.getItem('scout_admin_token');
202
+ const userEmail = (state.user?.email || '').toLowerCase();
203
+ if (adminToken || userEmail === 'rishishandilya40@gmail.com' || userEmail.includes('admin')) {
204
+ showAdminNavigationLink();
205
+ } else {
206
+ const checkRes = await fetch('/api/admin/check');
207
+ if (checkRes.ok) {
208
+ const checkData = await checkRes.json();
209
+ if (checkData.authorized) showAdminNavigationLink();
210
+ }
211
+ }
212
+ } catch { }
213
+ }
214
+
215
+ function showAdminNavigationLink() {
216
+ if (!document.getElementById('nav-admin-link')) {
217
+ const mainNav = getEl('main-nav');
218
+ if (mainNav) {
219
+ const a = document.createElement('a');
220
+ a.id = 'nav-admin-link';
221
+ a.href = '/admin';
222
+ a.className = 'nav-btn';
223
+ a.style.color = '#f06843';
224
+ a.innerHTML = '<i class="fa-solid fa-sliders"></i> Admin';
225
+ mainNav.appendChild(a);
226
+ }
227
+ }
228
+ }
229
+
182
230
  // Initialize Application
183
231
  document.addEventListener('DOMContentLoaded', async () => {
184
232
  highlightActiveNav();
@@ -189,6 +237,7 @@ document.addEventListener('DOMContentLoaded', async () => {
189
237
  initTerminalSimulator();
190
238
  renderAllDynamicComponents();
191
239
  await checkServerStatusAndSession();
240
+ await loadDynamicPricing();
192
241
  await checkPaymentRedirectCallback();
193
242
 
194
243
  if (getEl('pacman-canvas')) {
@@ -318,20 +367,29 @@ function openCheckoutModal(targetTier) {
318
367
  const isAnnual = state.billingCycle === 'annual';
319
368
  const tierInfo = TIER_DETAILS[targetTier] || TIER_DETAILS.pro;
320
369
 
370
+ const p = state.pricing || {
371
+ pro: { monthlyPriceINR: 50, annualPriceINR: 45, credits: 1000 },
372
+ enterprise: { monthlyPriceINR: 3999, annualPriceINR: 37990, credits: 10000 },
373
+ };
374
+
321
375
  let price = '0';
322
376
  let quota = '100 Credits / mo';
323
377
 
324
378
  if (targetTier === 'pro') {
325
- price = isAnnual ? '15' : '19';
326
- quota = '1,000 Credits / mo';
379
+ const inr = isAnnual ? (p.pro?.annualPriceINR || 45) : (p.pro?.monthlyPriceINR || 50);
380
+ price = inr.toLocaleString('en-IN');
381
+ quota = `${(p.pro?.credits || 1000).toLocaleString()} Credits / mo`;
327
382
  } else if (targetTier === 'enterprise') {
328
- price = isAnnual ? '39' : '49';
329
- quota = '10,000 Credits / mo';
383
+ const inr = isAnnual ? (p.enterprise?.annualPriceINR || 37990) : (p.enterprise?.monthlyPriceINR || 3999);
384
+ price = inr.toLocaleString('en-IN');
385
+ quota = `${(p.enterprise?.credits || 10000).toLocaleString()} Credits / mo`;
330
386
  }
331
387
 
332
388
  if (getEl('checkout-plan-name')) getEl('checkout-plan-name').innerText = tierInfo.name;
333
- if (getEl('checkout-billing-cycle')) getEl('checkout-billing-cycle').innerText = isAnnual ? 'Billed Annually (20% Off)' : 'Billed Monthly';
389
+ if (getEl('checkout-billing-cycle')) getEl('checkout-billing-cycle').innerText = isAnnual ? 'Billed Annually (Save more)' : 'Billed Monthly';
334
390
  if (getEl('checkout-plan-price')) getEl('checkout-plan-price').innerText = price;
391
+ const checkoutCurrency = document.querySelector('.checkout-price-display .price-currency');
392
+ if (checkoutCurrency) checkoutCurrency.innerText = '₹';
335
393
  if (getEl('checkout-price-period')) getEl('checkout-price-period').innerText = isAnnual ? '/ mo (annual)' : '/ mo';
336
394
  if (getEl('checkout-quota-val')) getEl('checkout-quota-val').innerText = quota;
337
395
 
@@ -426,14 +484,17 @@ function resumeSubscription() {
426
484
  // Render and initialize Razorpay button UI
427
485
  function renderRazorpayButton(targetTier) {
428
486
  const isAnnual = state.billingCycle === 'annual';
429
- const inrAmount = targetTier === 'enterprise' ? (isAnnual ? 37990 : 3999) : (isAnnual ? 15350 : 1599);
487
+ const p = state.pricing || {};
488
+ const inrAmount = targetTier === 'enterprise'
489
+ ? (isAnnual ? (p.enterprise?.annualPriceINR || 37990) : (p.enterprise?.monthlyPriceINR || 3999))
490
+ : (isAnnual ? (p.pro?.annualPriceINR || 45) : (p.pro?.monthlyPriceINR || 50));
430
491
  const btnRzp = getEl('btn-razorpay-checkout');
431
492
  if (!btnRzp) return;
432
493
 
433
494
  btnRzp.disabled = false;
434
495
  btnRzp.innerHTML = `
435
496
  <i class="fa-solid fa-bolt text-warning" style="font-size: 18px;"></i>
436
- <span>Pay with Razorpay</span>
497
+ <span>Pay ₹${inrAmount.toLocaleString('en-IN')} with Razorpay / UPI</span>
437
498
  `;
438
499
  }
439
500
 
@@ -441,7 +502,10 @@ function renderRazorpayButton(targetTier) {
441
502
  async function handleRazorpayCheckout() {
442
503
  const targetTier = pendingCheckoutTier || 'pro';
443
504
  const isAnnual = state.billingCycle === 'annual';
444
- const inrAmount = targetTier === 'enterprise' ? (isAnnual ? 37990 : 3999) : (isAnnual ? 15350 : 1599);
505
+ const p = state.pricing || {};
506
+ const inrAmount = targetTier === 'enterprise'
507
+ ? (isAnnual ? (p.enterprise?.annualPriceINR || 37990) : (p.enterprise?.monthlyPriceINR || 3999))
508
+ : (isAnnual ? (p.pro?.annualPriceINR || 45) : (p.pro?.monthlyPriceINR || 50));
445
509
  const amountInPaise = inrAmount * 100; // minimum 100 paise
446
510
 
447
511
  const btnRzp = getEl('btn-razorpay-checkout');
@@ -980,7 +1044,7 @@ function initTerminalSimulator() {
980
1044
  `;
981
1045
  } else if (lower.includes('status')) {
982
1046
  response.innerHTML = `
983
- <span class="term-green">✔ Scout CLI Engine: v8.0.9 Online</span><br>
1047
+ <span class="term-green">✔ Scout CLI Engine: v9.0.0 Online</span><br>
984
1048
  ↳ User: <strong>${escapeHtml(state.user ? state.user.name : 'Guest Session')}</strong><br>
985
1049
  ↳ Active Subscription: <strong>${escapeHtml(TIER_DETAILS[state.currentTier].name)}</strong><br>
986
1050
  ↳ Credit Quota: <strong>${state.byokEnabled ? 'BYOK Mode (Unlimited)' : `${state.creditsUsed} / ${state.creditsTotal} Credits Used`}</strong><br>
@@ -1224,11 +1288,19 @@ function renderTiersUI() {
1224
1288
  }
1225
1289
 
1226
1290
  const isAnnual = state.billingCycle === 'annual';
1227
- if (getEl('price-pro-val')) getEl('price-pro-val').innerText = isAnnual ? '15' : '19';
1291
+ const p = state.pricing || {};
1292
+ const proINR = isAnnual ? (p.pro?.annualPriceINR || 45) : (p.pro?.monthlyPriceINR || 50);
1293
+ const entINR = isAnnual ? (p.enterprise?.annualPriceINR || 37990) : (p.enterprise?.monthlyPriceINR || 3999);
1294
+
1295
+ if (getEl('price-pro-val')) getEl('price-pro-val').innerText = proINR;
1228
1296
  if (getEl('price-pro-period')) getEl('price-pro-period').innerText = isAnnual ? '/ month (billed annually)' : '/ month';
1297
+ const proCurrency = document.querySelector('#tier-card-pro .price-currency');
1298
+ if (proCurrency) proCurrency.innerText = '₹';
1229
1299
 
1230
- if (getEl('price-ent-val')) getEl('price-ent-val').innerText = isAnnual ? '39' : '49';
1300
+ if (getEl('price-ent-val')) getEl('price-ent-val').innerText = entINR.toLocaleString('en-IN');
1231
1301
  if (getEl('price-ent-period')) getEl('price-ent-period').innerText = isAnnual ? '/ month (billed annually)' : '/ month';
1302
+ const entCurrency = document.querySelector('#tier-card-enterprise .price-currency');
1303
+ if (entCurrency) entCurrency.innerText = '₹';
1232
1304
 
1233
1305
  ['free', 'pro', 'enterprise'].forEach((t) => {
1234
1306
  const card = getEl(`tier-card-${t}`);
@@ -1405,6 +1477,28 @@ async function handleSignIn(e) {
1405
1477
 
1406
1478
  if (!email || !password) return;
1407
1479
 
1480
+ // Check Master Admin Credentials
1481
+ const isMasterAdminAuth = (email.toLowerCase() === 'rishishandilya40@gmail.com' || email.toLowerCase().includes('admin')) && (password === 'scout_admin_2026' || password === 'admin');
1482
+ if (isMasterAdminAuth) {
1483
+ state.token = 'scout_admin_token_' + Date.now().toString(36);
1484
+ state.refreshToken = 'rt_' + Date.now().toString(36);
1485
+ state.user = {
1486
+ id: 'usr_admin_001',
1487
+ email: email,
1488
+ name: 'Scout Administrator',
1489
+ createdAt: new Date().toISOString(),
1490
+ };
1491
+ state.currentTier = 'pro';
1492
+ state.creditsTotal = 1000;
1493
+ state.creditsUsed = 0;
1494
+ sessionStorage.setItem('scout_admin_token', 'scout_admin_standalone_' + Date.now());
1495
+ saveSessionToStorage();
1496
+ updateUserUI();
1497
+ showToast('Authenticated as Scout Administrator! Redirecting to Control Center...', 'success');
1498
+ setTimeout(() => { window.location.href = '/admin'; }, 400);
1499
+ return;
1500
+ }
1501
+
1408
1502
  if (btnSubmit) {
1409
1503
  btnSubmit.disabled = true;
1410
1504
  btnSubmit.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Authenticating...';
package/web/styles.css CHANGED
@@ -1,5 +1,5 @@
1
1
  /* ==========================================================================
2
- FrontTerrain Scout — Design System & Visual Engine v8.0.9
2
+ FrontTerrain Scout — Design System & Visual Engine v9.0.0
3
3
  Inspired by HappyRobot, Linear.app & Vercel aesthetics
4
4
  ========================================================================== */
5
5
 
@@ -1063,7 +1063,7 @@ h1, h2, h3, h4, h5, h6 {
1063
1063
  .footer-links a:hover { color: var(--hr-rust); }
1064
1064
 
1065
1065
  /* ==========================================================================
1066
- Visual Perception & Live Screen Sharing Engine v8.0.9
1066
+ Visual Perception & Live Screen Sharing Engine v9.0.0
1067
1067
  ========================================================================== */
1068
1068
  .vision-banner {
1069
1069
  margin-bottom: 28px;