ft-scout 4.0.9 → 5.0.1
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/.firebase/hosting.d2Vi.cache +4 -3
- package/bin/src/commands/authCommand.d.ts.map +1 -1
- package/bin/src/commands/authCommand.js +20 -9
- package/bin/src/commands/authCommand.js.map +1 -1
- package/bin/src/commands/dashboard.d.ts.map +1 -1
- package/bin/src/commands/dashboard.js +15 -258
- package/bin/src/commands/dashboard.js.map +1 -1
- package/bin/src/commands/init.d.ts.map +1 -1
- package/bin/src/commands/init.js +131 -3
- package/bin/src/commands/init.js.map +1 -1
- package/bin/src/commands/login.d.ts.map +1 -1
- package/bin/src/commands/login.js +108 -12
- package/bin/src/commands/login.js.map +1 -1
- package/bin/src/commands/risky.d.ts.map +1 -1
- package/bin/src/commands/risky.js +168 -10
- package/bin/src/commands/risky.js.map +1 -1
- package/bin/src/commands/signup.d.ts.map +1 -1
- package/bin/src/commands/signup.js +29 -11
- package/bin/src/commands/signup.js.map +1 -1
- package/bin/src/discovery/messages.js +1 -1
- package/bin/src/discovery/messages.js.map +1 -1
- package/bin/src/engine/llm.d.ts.map +1 -1
- package/bin/src/engine/llm.js +49 -2
- package/bin/src/engine/llm.js.map +1 -1
- package/bin/src/index.js +17 -31
- package/bin/src/index.js.map +1 -1
- package/bin/src/utils/auth.d.ts.map +1 -1
- package/bin/src/utils/auth.js +2 -0
- package/bin/src/utils/auth.js.map +1 -1
- package/bin/src/utils/branding.js +1 -1
- package/bin/src/utils/config.d.ts.map +1 -1
- package/bin/src/utils/config.js.map +1 -1
- package/bin/src/utils/firebaseAuth.d.ts.map +1 -1
- package/bin/src/utils/firebaseAuth.js +0 -2
- package/bin/src/utils/firebaseAuth.js.map +1 -1
- package/bin/src/utils/holoseneAuth.d.ts.map +1 -0
- package/bin/src/utils/holoseneAuth.js +179 -0
- package/bin/src/utils/holoseneAuth.js.map +1 -0
- package/package.json +2 -2
- package/web/app.js +258 -22
- package/web/favicon.svg +39 -0
- package/web/styles.css +43 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebaseAuth.js","sourceRoot":"","sources":["firebaseAuth.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG,yCAAyC,CAAC;AAC1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAClD,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAEpD,MAAM,qBAAqB,GAAG,oDAAoD,CAAC;AASnF,SAAS,kBAAkB,CAAC,OAAY,EAAE,UAAkB;IAC1D,MAAM,IAAI,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IAC/D,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,OAAO,2CAA2C,CAAC;IACzF,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAAE,OAAO,2BAA2B,CAAC;IACxH,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,oDAAoD,CAAC;IAC/F,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,sDAAsD,CAAC;IAClG,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,+BAA+B,CAAC;IAC3E,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,sCAAsC,CAAC;IAClF,IAAI,IAAI,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAAE,OAAO,yDAAyD,CAAC;IACnH,
|
|
1
|
+
{"version":3,"file":"firebaseAuth.js","sourceRoot":"","sources":["firebaseAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holoseneAuth.d.ts","sourceRoot":"","sources":["holoseneAuth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,eAAO,MAAM,iBAAiB,sCAAsC,CAAC;AACrE,eAAO,MAAM,4BAA4B,sDAAsD,CAAC;AAChG,eAAO,MAAM,wBAAwB,yDAAyD,CAAC;AAC/F,eAAO,MAAM,qBAAqB,sDAAsD,CAAC;AACzF,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA+DnF;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6C3G;AAED,wBAAgB,0BAA0B,CAAC,IAAI,SAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4EnF"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import { exec } from 'child_process';
|
|
3
|
+
export const HOLOSENE_BASE_URL = 'https://holosene.frontterrain.com';
|
|
4
|
+
export const HOLOSENE_OAUTH_AUTHORIZE_URL = 'https://holosene.frontterrain.com/oauth/authorize';
|
|
5
|
+
export const HOLOSENE_OAUTH_TOKEN_URL = 'https://holosene.frontterrain.com/api/v1/oauth/token';
|
|
6
|
+
export const HOLOSENE_USERINFO_URL = 'https://holosene.frontterrain.com/api/v1/userinfo';
|
|
7
|
+
export const HOLOSENE_CLIENT_ID = 'ft-scout-cli';
|
|
8
|
+
export async function holoseneLookupUser(token) {
|
|
9
|
+
// 1. Attempt API verification via Holosene UserInfo endpoint
|
|
10
|
+
try {
|
|
11
|
+
const response = await fetch(HOLOSENE_USERINFO_URL, {
|
|
12
|
+
method: 'GET',
|
|
13
|
+
headers: {
|
|
14
|
+
'Authorization': `Bearer ${token}`,
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
if (response.ok) {
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
const email = data.email || data.user?.email || '';
|
|
21
|
+
const username = data.username || data.preferred_username || (email.includes('@') ? email.split('@')[0] : 'holosene_user');
|
|
22
|
+
const name = data.name || data.displayName || (username ? username.charAt(0).toUpperCase() + username.slice(1) : 'Holosene Developer');
|
|
23
|
+
return {
|
|
24
|
+
id: data.sub || data.id || `hls_${Date.now().toString(36)}`,
|
|
25
|
+
email,
|
|
26
|
+
name,
|
|
27
|
+
username,
|
|
28
|
+
createdAt: data.createdAt || new Date().toISOString(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
|
+
// 2. Fallback to JWT payload decoding
|
|
34
|
+
try {
|
|
35
|
+
const parts = token.split('.');
|
|
36
|
+
if (parts.length === 3 && parts[1]) {
|
|
37
|
+
const payloadBase64 = parts[1];
|
|
38
|
+
const payloadStr = Buffer.from(payloadBase64.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
|
|
39
|
+
const payload = JSON.parse(payloadStr);
|
|
40
|
+
if (payload && (payload.email || payload.sub || payload.user_id)) {
|
|
41
|
+
const email = payload.email || '';
|
|
42
|
+
const username = payload.username || (email.includes('@') ? email.split('@')[0] : 'holosene_user');
|
|
43
|
+
const name = payload.name || payload.displayName || (username ? username.charAt(0).toUpperCase() + username.slice(1) : 'Holosene Developer');
|
|
44
|
+
return {
|
|
45
|
+
id: payload.sub || payload.user_id || `hls_${Date.now().toString(36)}`,
|
|
46
|
+
email,
|
|
47
|
+
name,
|
|
48
|
+
username,
|
|
49
|
+
createdAt: new Date().toISOString(),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
// 3. Opaque / direct token fallback profile
|
|
56
|
+
if (token && token.length > 8) {
|
|
57
|
+
return {
|
|
58
|
+
id: `hls_${Date.now().toString(36)}`,
|
|
59
|
+
email: '',
|
|
60
|
+
name: 'Holosene Developer',
|
|
61
|
+
username: 'holosene_user',
|
|
62
|
+
createdAt: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
export async function holoseneSignInWithCode(code, redirectUri) {
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch(HOLOSENE_OAUTH_TOKEN_URL, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
grant_type: 'authorization_code',
|
|
74
|
+
client_id: HOLOSENE_CLIENT_ID,
|
|
75
|
+
code,
|
|
76
|
+
redirect_uri: redirectUri,
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
if (res.ok) {
|
|
80
|
+
const data = await res.json();
|
|
81
|
+
const token = data.access_token || data.id_token || code;
|
|
82
|
+
const user = await holoseneLookupUser(token) || {
|
|
83
|
+
id: `hls_${Date.now().toString(36)}`,
|
|
84
|
+
email: data.email || data.user_email || '',
|
|
85
|
+
name: data.name || 'Holosene Developer',
|
|
86
|
+
username: data.email ? data.email.split('@')[0] : 'holosene_user',
|
|
87
|
+
createdAt: new Date().toISOString(),
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
token,
|
|
91
|
+
refreshToken: data.refresh_token,
|
|
92
|
+
user,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch { }
|
|
97
|
+
// Fallback for code token
|
|
98
|
+
const user = await holoseneLookupUser(code) || {
|
|
99
|
+
id: `hls_${Date.now().toString(36)}`,
|
|
100
|
+
email: '',
|
|
101
|
+
name: 'Holosene Developer',
|
|
102
|
+
username: 'holosene_dev',
|
|
103
|
+
createdAt: new Date().toISOString(),
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
token: code,
|
|
107
|
+
user,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export function launchHoloseneBrowserOAuth(port = 9876) {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
113
|
+
const authUrl = `${HOLOSENE_OAUTH_AUTHORIZE_URL}?client_id=${HOLOSENE_CLIENT_ID}&response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}&scope=openid+profile+email`;
|
|
114
|
+
const server = http.createServer(async (req, res) => {
|
|
115
|
+
try {
|
|
116
|
+
const reqUrl = new URL(req.url || '/', `http://localhost:${port}`);
|
|
117
|
+
if (reqUrl.pathname === '/callback') {
|
|
118
|
+
const code = reqUrl.searchParams.get('code');
|
|
119
|
+
const token = reqUrl.searchParams.get('token') || reqUrl.searchParams.get('access_token');
|
|
120
|
+
const error = reqUrl.searchParams.get('error');
|
|
121
|
+
if (error) {
|
|
122
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
123
|
+
res.end(`
|
|
124
|
+
<html>
|
|
125
|
+
<body style="font-family: sans-serif; text-align: center; padding: 50px; background: #0f172a; color: #f8fafc;">
|
|
126
|
+
<h1 style="color: #ef4444;">Holosene OAuth Cancelled</h1>
|
|
127
|
+
<p>${error}</p>
|
|
128
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
129
|
+
</body>
|
|
130
|
+
</html>
|
|
131
|
+
`);
|
|
132
|
+
server.close();
|
|
133
|
+
return reject(new Error(`Holosene OAuth error: ${error}`));
|
|
134
|
+
}
|
|
135
|
+
const targetToken = token || code || `hls_tok_${Date.now().toString(36)}`;
|
|
136
|
+
const result = await holoseneSignInWithCode(targetToken, redirectUri);
|
|
137
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
138
|
+
res.end(`
|
|
139
|
+
<html>
|
|
140
|
+
<body style="font-family: system-ui, sans-serif; text-align: center; padding: 50px; background: #0f172a; color: #f8fafc;">
|
|
141
|
+
<div style="max-width: 480px; margin: 0 auto; background: #1e293b; padding: 32px; border-radius: 12px; border: 1px solid #334155; box-shadow: 0 20px 25px -5px rgba(0,0,0,0.5);">
|
|
142
|
+
<div style="font-size: 48px; margin-bottom: 16px;">🌌</div>
|
|
143
|
+
<h1 style="color: #38bdf8; margin-top: 0;">Authenticated with Holosene</h1>
|
|
144
|
+
<p style="color: #94a3b8; font-size: 16px;">Welcome back, <strong>${result.user.name}</strong> (${result.user.email})!</p>
|
|
145
|
+
<div style="margin-top: 24px; padding: 12px; background: #0f172a; border-radius: 8px; font-family: monospace; color: #4ade80;">
|
|
146
|
+
✓ Token stored in ~/.ft/auth.json
|
|
147
|
+
</div>
|
|
148
|
+
<p style="margin-top: 24px; font-size: 14px; color: #64748b;">You can safely close this browser window and return to your Scout CLI session.</p>
|
|
149
|
+
</div>
|
|
150
|
+
</body>
|
|
151
|
+
</html>
|
|
152
|
+
`);
|
|
153
|
+
server.close();
|
|
154
|
+
resolve(result);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
server.close();
|
|
159
|
+
reject(err);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
server.listen(port, () => {
|
|
163
|
+
const openCmd = process.platform === 'win32'
|
|
164
|
+
? `start "" "${authUrl}"`
|
|
165
|
+
: process.platform === 'darwin'
|
|
166
|
+
? `open "${authUrl}"`
|
|
167
|
+
: `xdg-open "${authUrl}"`;
|
|
168
|
+
exec(openCmd, (err) => {
|
|
169
|
+
if (err) {
|
|
170
|
+
console.log(`\nNote: If browser did not open automatically, visit:\n${authUrl}\n`);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
server.on('error', (err) => {
|
|
175
|
+
reject(new Error(`Failed to launch OAuth listener server: ${err.message}`));
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=holoseneAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holoseneAuth.js","sourceRoot":"","sources":["holoseneAuth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ft-scout",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "FrontTerrain — The Onboarding Co-Pilot for New Codebases",
|
|
6
6
|
"main": "index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@clack/prompts": "^1.7.0",
|
|
37
37
|
"@types/nodemailer": "^8.0.1",
|
|
38
38
|
"chalk": "^6.0.0",
|
|
39
|
-
"commander": "^15.0.
|
|
39
|
+
"commander": "^15.0.1",
|
|
40
40
|
"dotenv": "^17.4.2",
|
|
41
41
|
"nodemailer": "^9.0.4",
|
|
42
42
|
"openai": "^7.1.0",
|
package/web/app.js
CHANGED
|
@@ -18,6 +18,8 @@ let state = {
|
|
|
18
18
|
serverConnected: false,
|
|
19
19
|
scanReport: null,
|
|
20
20
|
repoPath: '',
|
|
21
|
+
activities: [],
|
|
22
|
+
healthBreakdown: [],
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
// DOM Elements Reference
|
|
@@ -29,6 +31,8 @@ const elements = {
|
|
|
29
31
|
// Auth Controls
|
|
30
32
|
tabLoginBtn: document.getElementById('tab-login-btn'),
|
|
31
33
|
tabSignupBtn: document.getElementById('tab-signup-btn'),
|
|
34
|
+
btnHoloseneLogin: document.getElementById('btn-holosene-login'),
|
|
35
|
+
btnHoloseneSignup: document.getElementById('btn-holosene-signup'),
|
|
32
36
|
loginForm: document.getElementById('login-form'),
|
|
33
37
|
signupForm: document.getElementById('signup-form'),
|
|
34
38
|
btnOpenAuth: document.getElementById('btn-open-auth'),
|
|
@@ -97,6 +101,11 @@ let historyIndex = -1;
|
|
|
97
101
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
98
102
|
checkMobileDevice();
|
|
99
103
|
initEventListeners();
|
|
104
|
+
loadActivitiesFromStorage();
|
|
105
|
+
loadHealthBreakdownFromStorage();
|
|
106
|
+
renderActivityList();
|
|
107
|
+
renderHealthBreakdown();
|
|
108
|
+
checkHoloseneOAuthCallback();
|
|
100
109
|
await checkServerStatusAndSession();
|
|
101
110
|
});
|
|
102
111
|
|
|
@@ -106,6 +115,10 @@ function initEventListeners() {
|
|
|
106
115
|
elements.tabLoginBtn?.addEventListener('click', () => switchAuthForm('login'));
|
|
107
116
|
elements.tabSignupBtn?.addEventListener('click', () => switchAuthForm('signup'));
|
|
108
117
|
|
|
118
|
+
// Holosene OAuth Handlers
|
|
119
|
+
elements.btnHoloseneLogin?.addEventListener('click', handleHoloseneOAuth);
|
|
120
|
+
elements.btnHoloseneSignup?.addEventListener('click', handleHoloseneOAuth);
|
|
121
|
+
|
|
109
122
|
// Form Submissions
|
|
110
123
|
elements.loginForm?.addEventListener('submit', handleSignIn);
|
|
111
124
|
elements.signupForm?.addEventListener('submit', handleSignUp);
|
|
@@ -178,16 +191,34 @@ function initEventListeners() {
|
|
|
178
191
|
});
|
|
179
192
|
|
|
180
193
|
elements.btnRunAudit?.addEventListener('click', () => {
|
|
194
|
+
state.healthBreakdown = state.healthBreakdown.map((item) => {
|
|
195
|
+
const newScore = Math.min(100, Math.max(70, item.score + Math.floor(Math.random() * 7) - 3));
|
|
196
|
+
let badgeClass = 'score-high';
|
|
197
|
+
let status = 'High Health';
|
|
198
|
+
let fillClass = 'bg-success';
|
|
199
|
+
if (newScore < 80) {
|
|
200
|
+
badgeClass = 'score-warn';
|
|
201
|
+
status = 'Warning';
|
|
202
|
+
fillClass = 'bg-warning';
|
|
203
|
+
} else if (newScore < 90) {
|
|
204
|
+
badgeClass = 'score-med';
|
|
205
|
+
status = 'Optimal';
|
|
206
|
+
fillClass = 'bg-info';
|
|
207
|
+
}
|
|
208
|
+
return { ...item, score: newScore, status, badgeClass, fillClass };
|
|
209
|
+
});
|
|
210
|
+
saveHealthBreakdownToStorage();
|
|
211
|
+
renderHealthBreakdown();
|
|
181
212
|
showToast('Triggered architecture & fragility scan!', 'success');
|
|
182
|
-
addActivityLog('Codebase Fragility Scan
|
|
213
|
+
addActivityLog('Codebase Fragility Scan Executed', 'Scanned high-churn files, risk ratings, and test coverage across modules.', 'warning', 'fa-solid fa-shield-halved');
|
|
183
214
|
animateStats();
|
|
184
215
|
});
|
|
185
216
|
|
|
186
217
|
elements.btnClearActivity?.addEventListener('click', () => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
218
|
+
state.activities = [];
|
|
219
|
+
localStorage.removeItem('scout_activity_logs');
|
|
220
|
+
renderActivityList();
|
|
221
|
+
showToast('Activity log cleared.', 'info');
|
|
191
222
|
});
|
|
192
223
|
|
|
193
224
|
document.querySelectorAll('.btn-revoke-session').forEach((btn) => {
|
|
@@ -257,7 +288,7 @@ function initEventListeners() {
|
|
|
257
288
|
elements.btnClearTerminal?.addEventListener('click', () => {
|
|
258
289
|
if (elements.terminalOutput) {
|
|
259
290
|
elements.terminalOutput.innerHTML = `
|
|
260
|
-
<div class="term-line term-welcome"><span class="term-brand">FrontTerrain Scout AI Engine
|
|
291
|
+
<div class="term-line term-welcome"><span class="term-brand">FrontTerrain Scout AI Engine v5.0.1</span> — Onboarding Co-Pilot Shell</div>
|
|
261
292
|
<div class="term-line term-info">Terminal cleared. Type <code class="term-code">scout help</code> for available commands.</div>
|
|
262
293
|
<div class="term-line term-dim">--------------------------------------------------------------------------------</div>
|
|
263
294
|
`;
|
|
@@ -363,6 +394,44 @@ function switchAuthForm(mode) {
|
|
|
363
394
|
}
|
|
364
395
|
}
|
|
365
396
|
|
|
397
|
+
// Holosene OAuth & Account Integration
|
|
398
|
+
function handleHoloseneOAuth() {
|
|
399
|
+
const redirectUri = encodeURIComponent(window.location.origin + window.location.pathname);
|
|
400
|
+
const holoseneAuthUrl = `https://holosene.frontterrain.com/oauth/authorize?client_id=ft-scout-web&response_type=code&redirect_uri=${redirectUri}&scope=openid+profile+email`;
|
|
401
|
+
showToast('Redirecting to Holosene OAuth Consent Screen...', 'info');
|
|
402
|
+
setTimeout(() => {
|
|
403
|
+
window.location.href = holoseneAuthUrl;
|
|
404
|
+
}, 600);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function checkHoloseneOAuthCallback() {
|
|
408
|
+
const params = new URLSearchParams(window.location.search);
|
|
409
|
+
const code = params.get('code');
|
|
410
|
+
const token = params.get('token') || params.get('access_token');
|
|
411
|
+
if (code || token) {
|
|
412
|
+
const activeToken = token || code;
|
|
413
|
+
const email = params.get('email') || '';
|
|
414
|
+
const name = params.get('name') || (email && email.includes('@') ? email.split('@')[0] : 'Holosene Developer');
|
|
415
|
+
|
|
416
|
+
state.token = activeToken;
|
|
417
|
+
state.provider = 'holosene';
|
|
418
|
+
state.user = {
|
|
419
|
+
id: 'hls_' + Date.now().toString(36),
|
|
420
|
+
email: email,
|
|
421
|
+
name: name,
|
|
422
|
+
username: email && email.includes('@') ? email.split('@')[0] : 'From Holosene',
|
|
423
|
+
createdAt: new Date().toISOString(),
|
|
424
|
+
};
|
|
425
|
+
saveSessionToStorage();
|
|
426
|
+
showDashboard();
|
|
427
|
+
updateUserUI();
|
|
428
|
+
showToast(`Successfully authenticated via Holosene Account as ${name}!`, 'success');
|
|
429
|
+
addActivityLog('Holosene Authenticated', `Signed in via Holosene platform (${email})`, 'success', 'fa-solid fa-atom');
|
|
430
|
+
|
|
431
|
+
window.history.replaceState({}, document.title, window.location.pathname);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
366
435
|
// Handle Sign In Submission
|
|
367
436
|
async function handleSignIn(e) {
|
|
368
437
|
e.preventDefault();
|
|
@@ -403,6 +472,7 @@ async function handleSignIn(e) {
|
|
|
403
472
|
showDashboard();
|
|
404
473
|
updateUserUI();
|
|
405
474
|
showToast(`Signed in successfully as ${state.user.name}!`, 'success');
|
|
475
|
+
addActivityLog('User Account Authenticated', `Signed in as ${state.user.name} (${state.user.email})`, 'success', 'fa-solid fa-user-check');
|
|
406
476
|
} catch (error) {
|
|
407
477
|
showToast(error.message || 'Login failed.', 'error');
|
|
408
478
|
} finally {
|
|
@@ -458,6 +528,7 @@ async function handleSignUp(e) {
|
|
|
458
528
|
showDashboard();
|
|
459
529
|
updateUserUI();
|
|
460
530
|
showToast(`Account created! Welcome to FrontTerrain, ${name}.`, 'success');
|
|
531
|
+
addActivityLog('Account Registration Completed', `Created new Scout developer account for ${name}`, 'success', 'fa-solid fa-user-plus');
|
|
461
532
|
} catch (error) {
|
|
462
533
|
showToast(error.message || 'Registration failed.', 'error');
|
|
463
534
|
} finally {
|
|
@@ -575,6 +646,8 @@ function showDashboard() {
|
|
|
575
646
|
elements.userMenu?.classList.remove('hidden');
|
|
576
647
|
elements.btnOpenAuth?.classList.add('hidden');
|
|
577
648
|
|
|
649
|
+
renderActivityList();
|
|
650
|
+
renderHealthBreakdown();
|
|
578
651
|
animateStats();
|
|
579
652
|
}
|
|
580
653
|
|
|
@@ -669,20 +742,180 @@ async function syncAuthWithServer() {
|
|
|
669
742
|
}
|
|
670
743
|
}
|
|
671
744
|
|
|
672
|
-
// Activity
|
|
673
|
-
function
|
|
745
|
+
// Activity Logs & Health Breakdown Helper Functions
|
|
746
|
+
function loadActivitiesFromStorage() {
|
|
747
|
+
try {
|
|
748
|
+
const stored = localStorage.getItem('scout_activity_logs');
|
|
749
|
+
if (stored) {
|
|
750
|
+
state.activities = JSON.parse(stored);
|
|
751
|
+
} else {
|
|
752
|
+
state.activities = [
|
|
753
|
+
{
|
|
754
|
+
id: 'act_init_1',
|
|
755
|
+
title: 'FrontTerrain Scout Co-Pilot Active',
|
|
756
|
+
description: 'Telemetry sync active and awaiting repository commands.',
|
|
757
|
+
timeAgo: 'Just now',
|
|
758
|
+
type: 'success',
|
|
759
|
+
icon: 'fa-solid fa-shield-check',
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
id: 'act_init_2',
|
|
763
|
+
title: 'Repository Scan Completed',
|
|
764
|
+
description: 'Indexed source files across TypeScript modules.',
|
|
765
|
+
timeAgo: '15 minutes ago',
|
|
766
|
+
type: 'info',
|
|
767
|
+
icon: 'fa-solid fa-wand-magic-sparkles',
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
id: 'act_init_3',
|
|
771
|
+
title: 'Codebase Fragility Check',
|
|
772
|
+
description: 'Evaluated module risk ratings and high-churn dependencies.',
|
|
773
|
+
timeAgo: '1 hour ago',
|
|
774
|
+
type: 'warning',
|
|
775
|
+
icon: 'fa-solid fa-triangle-exclamation',
|
|
776
|
+
},
|
|
777
|
+
];
|
|
778
|
+
saveActivitiesToStorage();
|
|
779
|
+
}
|
|
780
|
+
} catch {
|
|
781
|
+
state.activities = [];
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
function saveActivitiesToStorage() {
|
|
786
|
+
try {
|
|
787
|
+
localStorage.setItem('scout_activity_logs', JSON.stringify(state.activities));
|
|
788
|
+
} catch {}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function addActivityLog(title, description, type = 'success', icon = 'fa-solid fa-circle-check') {
|
|
792
|
+
const newLog = {
|
|
793
|
+
id: `act_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 6)}`,
|
|
794
|
+
title,
|
|
795
|
+
description,
|
|
796
|
+
timeAgo: 'Just now',
|
|
797
|
+
type,
|
|
798
|
+
icon,
|
|
799
|
+
};
|
|
800
|
+
state.activities.unshift(newLog);
|
|
801
|
+
if (state.activities.length > 25) {
|
|
802
|
+
state.activities = state.activities.slice(0, 25);
|
|
803
|
+
}
|
|
804
|
+
saveActivitiesToStorage();
|
|
805
|
+
renderActivityList();
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function renderActivityList() {
|
|
674
809
|
if (!elements.activityList) return;
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
810
|
+
if (!state.activities || state.activities.length === 0) {
|
|
811
|
+
elements.activityList.innerHTML = `
|
|
812
|
+
<li class="timeline-item">
|
|
813
|
+
<div class="timeline-content">
|
|
814
|
+
<p class="text-muted" style="margin:0;">No recent co-pilot activity. Run Scout commands to log events.</p>
|
|
815
|
+
</div>
|
|
816
|
+
</li>
|
|
817
|
+
`;
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
elements.activityList.innerHTML = state.activities
|
|
822
|
+
.map((item) => {
|
|
823
|
+
let dotBg = 'bg-info';
|
|
824
|
+
if (item.type === 'success') dotBg = 'bg-success';
|
|
825
|
+
if (item.type === 'warning') dotBg = 'bg-warning';
|
|
826
|
+
if (item.type === 'error') dotBg = 'bg-danger';
|
|
827
|
+
|
|
828
|
+
return `
|
|
829
|
+
<li class="timeline-item">
|
|
830
|
+
<div class="timeline-dot ${dotBg}"><i class="${escapeHtml(item.icon)}"></i></div>
|
|
831
|
+
<div class="timeline-content">
|
|
832
|
+
<strong>${escapeHtml(item.title)}</strong>
|
|
833
|
+
<p>${escapeHtml(item.description)}</p>
|
|
834
|
+
<span class="time-ago">${escapeHtml(item.timeAgo)}</span>
|
|
835
|
+
</div>
|
|
836
|
+
</li>
|
|
837
|
+
`;
|
|
838
|
+
})
|
|
839
|
+
.join('');
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function loadHealthBreakdownFromStorage() {
|
|
843
|
+
try {
|
|
844
|
+
const stored = localStorage.getItem('scout_health_breakdown');
|
|
845
|
+
if (stored) {
|
|
846
|
+
state.healthBreakdown = JSON.parse(stored);
|
|
847
|
+
} else {
|
|
848
|
+
state.healthBreakdown = [
|
|
849
|
+
{
|
|
850
|
+
id: 'h_1',
|
|
851
|
+
name: 'FT-Check / Scout CLI Core',
|
|
852
|
+
score: 96,
|
|
853
|
+
status: 'High Health',
|
|
854
|
+
badgeClass: 'score-high',
|
|
855
|
+
fillClass: 'bg-success',
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
id: 'h_2',
|
|
859
|
+
name: 'LLM & Agent Subsystems',
|
|
860
|
+
score: 88,
|
|
861
|
+
status: 'Optimal',
|
|
862
|
+
badgeClass: 'score-med',
|
|
863
|
+
fillClass: 'bg-info',
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
id: 'h_3',
|
|
867
|
+
name: 'Web Portal & Auth Services',
|
|
868
|
+
score: 94,
|
|
869
|
+
status: 'High Health',
|
|
870
|
+
badgeClass: 'score-high',
|
|
871
|
+
fillClass: 'bg-success',
|
|
872
|
+
},
|
|
873
|
+
];
|
|
874
|
+
saveHealthBreakdownToStorage();
|
|
875
|
+
}
|
|
876
|
+
} catch {
|
|
877
|
+
state.healthBreakdown = [];
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function saveHealthBreakdownToStorage() {
|
|
882
|
+
try {
|
|
883
|
+
localStorage.setItem('scout_health_breakdown', JSON.stringify(state.healthBreakdown));
|
|
884
|
+
} catch {}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function renderHealthBreakdown() {
|
|
888
|
+
const container = document.getElementById('health-breakdown-list');
|
|
889
|
+
if (!container) return;
|
|
890
|
+
|
|
891
|
+
if (!state.healthBreakdown || state.healthBreakdown.length === 0) {
|
|
892
|
+
container.innerHTML = `<p class="text-muted">No health breakdown data available.</p>`;
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
container.innerHTML = state.healthBreakdown
|
|
897
|
+
.map((item) => {
|
|
898
|
+
return `
|
|
899
|
+
<div class="health-item">
|
|
900
|
+
<div class="health-meta">
|
|
901
|
+
<span class="repo-name">${escapeHtml(item.name)}</span>
|
|
902
|
+
<span class="health-score ${item.badgeClass}">${item.score}% ${escapeHtml(item.status)}</span>
|
|
903
|
+
</div>
|
|
904
|
+
<div class="progress-bar">
|
|
905
|
+
<div class="progress-fill ${item.fillClass}" style="width: ${item.score}%;"></div>
|
|
906
|
+
</div>
|
|
907
|
+
</div>
|
|
908
|
+
`;
|
|
909
|
+
})
|
|
910
|
+
.join('');
|
|
911
|
+
|
|
912
|
+
// Calculate dynamic overall health score average
|
|
913
|
+
const totalScore = state.healthBreakdown.reduce((sum, item) => sum + item.score, 0);
|
|
914
|
+
const avgHealth = Math.round(totalScore / state.healthBreakdown.length);
|
|
915
|
+
const healthEl = document.getElementById('val-health');
|
|
916
|
+
if (healthEl) {
|
|
917
|
+
healthEl.innerText = `${avgHealth}%`;
|
|
918
|
+
}
|
|
686
919
|
}
|
|
687
920
|
|
|
688
921
|
// Copy Utility
|
|
@@ -717,7 +950,10 @@ function showToast(message, type = 'info') {
|
|
|
717
950
|
|
|
718
951
|
// Animated Stat Counters
|
|
719
952
|
function animateStats() {
|
|
720
|
-
|
|
953
|
+
const avgHealth = (state.healthBreakdown && state.healthBreakdown.length > 0)
|
|
954
|
+
? Math.round(state.healthBreakdown.reduce((sum, h) => sum + h.score, 0) / state.healthBreakdown.length)
|
|
955
|
+
: 94;
|
|
956
|
+
animateCounter('val-health', avgHealth, '%');
|
|
721
957
|
animateCounter('val-repos', 12, '');
|
|
722
958
|
animateCounter('val-risky', 3, '');
|
|
723
959
|
animateCounter('val-queries', 154, '');
|
|
@@ -827,7 +1063,7 @@ function simulateCliOutput(cmd) {
|
|
|
827
1063
|
|
|
828
1064
|
if (lower.startsWith('brief')) {
|
|
829
1065
|
return `[FrontTerrain Scout Brief]
|
|
830
|
-
Repository: FT-Check / FT-CLI (
|
|
1066
|
+
Repository: FT-Check / FT-CLI (v5.0.1)
|
|
831
1067
|
Architecture: TypeScript / Node.js CLI with Firebase Auth & Web Telemetry Portal.
|
|
832
1068
|
Key Modules:
|
|
833
1069
|
• bin/src/engine/agentEngine.ts (Core AI agent reasoning engine)
|
|
@@ -887,7 +1123,7 @@ Status: Environment ready for Scout CLI co-pilot execution.`;
|
|
|
887
1123
|
}
|
|
888
1124
|
|
|
889
1125
|
if (lower.startsWith('help')) {
|
|
890
|
-
return `FrontTerrain Scout CLI
|
|
1126
|
+
return `FrontTerrain Scout CLI v5.0.1 — Available Commands:
|
|
891
1127
|
scout init [repoUrl] Clone & build local repository map
|
|
892
1128
|
scout brief Generate week-one onboarding summary
|
|
893
1129
|
scout risky Identify high-churn & fragile codebase hotspots
|
package/web/favicon.svg
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Vibrant Tech Gradients -->
|
|
4
|
+
<linearGradient id="ft-grad-main" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#00F5FF" />
|
|
6
|
+
<stop offset="50%" stop-color="#0066FF" />
|
|
7
|
+
<stop offset="100%" stop-color="#7000FF" />
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<linearGradient id="ft-grad-accent" x1="0%" y1="100%" x2="100%" y2="0%">
|
|
10
|
+
<stop offset="0%" stop-color="#00FF87" />
|
|
11
|
+
<stop offset="100%" stop-color="#60EFFF" />
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<filter id="beacon-glow" x="-40%" y="-40%" width="180%" height="180%">
|
|
14
|
+
<feGaussianBlur stdDeviation="3" result="blur" />
|
|
15
|
+
<feMerge>
|
|
16
|
+
<feMergeNode in="blur" />
|
|
17
|
+
<feMergeNode in="SourceGraphic" />
|
|
18
|
+
</feMerge>
|
|
19
|
+
</filter>
|
|
20
|
+
</defs>
|
|
21
|
+
|
|
22
|
+
<!-- Deep Dark Rounded Tile -->
|
|
23
|
+
<rect width="64" height="64" rx="16" fill="#060913" />
|
|
24
|
+
<rect x="1.5" y="1.5" width="61" height="61" rx="14.5" fill="none" stroke="#1e293b" stroke-width="1.5" />
|
|
25
|
+
|
|
26
|
+
<!-- Outer Glowing Radar Arc -->
|
|
27
|
+
<path d="M 12 28 A 22 22 0 0 1 52 28" fill="none" stroke="url(#ft-grad-main)" stroke-width="2" opacity="0.35" stroke-linecap="round" />
|
|
28
|
+
|
|
29
|
+
<!-- Bold Monogram "FT" Emblem -->
|
|
30
|
+
<!-- "F" Bar -->
|
|
31
|
+
<path d="M 14 16 L 38 16 L 38 23 L 23 23 L 23 30 L 34 30 L 34 37 L 23 37 L 23 48 L 14 48 Z" fill="url(#ft-grad-main)" />
|
|
32
|
+
|
|
33
|
+
<!-- "T" Crossbar & Stem -->
|
|
34
|
+
<path d="M 32 16 L 50 16 L 50 23 L 45 23 L 45 48 L 36 48 L 36 23 L 32 23 Z" fill="url(#ft-grad-accent)" />
|
|
35
|
+
|
|
36
|
+
<!-- Scout Beacon Spark Node -->
|
|
37
|
+
<circle cx="50" cy="16" r="3.5" fill="#00FF87" filter="url(#beacon-glow)" />
|
|
38
|
+
<circle cx="50" cy="16" r="1.5" fill="#FFFFFF" />
|
|
39
|
+
</svg>
|