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,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
styles.css,1786177678984,5c25ac2a2bf5e5b3877f6ed5d8b25f9038eda8ab6ea3c4a3ecd43a6337cc62c8
|
|
2
|
+
index.html,1786177670585,c8aa9c5585633be676ed89528d28e37fd950f90a5c6a0fb5ccdc976317f669d7
|
|
3
|
+
favicon.svg,1786121352486,821922ce0d598edd137f0c1bea7389ae7728313f9b9d4ad83775c8c1bfaa47a9
|
|
4
|
+
app.js,1786179145758,d08e9179a7093ea09d096d2d6245a7e54d905bc65aa0292735fbf3c591d49f09
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authCommand.d.ts","sourceRoot":"","sources":["authCommand.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"authCommand.d.ts","sourceRoot":"","sources":["authCommand.ts"],"names":[],"mappings":"AAMA,wBAAsB,gBAAgB,kBA2CrC"}
|
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { safeNote } from '../utils/markdown.js';
|
|
3
3
|
import { loadAuthConfig } from '../utils/auth.js';
|
|
4
|
-
import { firebaseLookupToken
|
|
4
|
+
import { firebaseLookupToken } from '../utils/firebaseAuth.js';
|
|
5
|
+
import { holoseneLookupUser } from '../utils/holoseneAuth.js';
|
|
5
6
|
export async function handleAuthStatus() {
|
|
6
7
|
const auth = loadAuthConfig();
|
|
7
8
|
if (!auth.token || !auth.user) {
|
|
8
9
|
safeNote(`Status: ${chalk.bold.red('Not Logged In')}\n\n` +
|
|
9
|
-
`Firebase Tenant: ${chalk.bold.yellow(FIREBASE_TENANT_ID)} (Project: ${FIREBASE_PROJECT_ID})\n` +
|
|
10
10
|
`No active session found in ${chalk.yellow('~/.ft/auth.json')}.\n\n` +
|
|
11
|
-
`Run ${chalk.cyan('
|
|
11
|
+
`Run ${chalk.cyan('scout login')} to sign in or ${chalk.cyan('scout signup')} to create an account.`, 'π FrontTerrain Scout Auth Status');
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const isHolosene = auth.provider === 'holosene';
|
|
15
|
+
let liveVerified = false;
|
|
16
|
+
if (isHolosene) {
|
|
17
|
+
const hUser = await holoseneLookupUser(auth.token);
|
|
18
|
+
liveVerified = Boolean(hUser);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const verification = await firebaseLookupToken(auth.token);
|
|
22
|
+
liveVerified = verification.valid;
|
|
23
|
+
}
|
|
24
|
+
const liveStatus = liveVerified
|
|
16
25
|
? chalk.bold.green('Authenticated (Live Verified)')
|
|
17
26
|
: chalk.bold.yellow('Session Active (Local cache)');
|
|
18
|
-
const
|
|
19
|
-
?
|
|
20
|
-
: '
|
|
27
|
+
const providerBadge = isHolosene
|
|
28
|
+
? chalk.bold.magenta('π Holosene OAuth (holosene.frontterrain.com)')
|
|
29
|
+
: chalk.bold.cyan('π₯ Firebase Auth');
|
|
21
30
|
const loggedInTime = auth.loggedInAt ? new Date(auth.loggedInAt).toLocaleString() : 'Active session';
|
|
22
|
-
safeNote(`Status: ${liveStatus}\n
|
|
31
|
+
safeNote(`Status: ${liveStatus}\n` +
|
|
32
|
+
`Auth Provider: ${providerBadge}\n\n` +
|
|
23
33
|
`User Name: ${chalk.bold(auth.user.name)}\n` +
|
|
24
34
|
`User Email: ${chalk.cyan(auth.user.email)}\n` +
|
|
35
|
+
`Username: ${chalk.dim(auth.user.username || 'n/a')}\n` +
|
|
25
36
|
`Logged In At: ${loggedInTime}\n`, 'π FrontTerrain Auth Status');
|
|
26
37
|
}
|
|
27
38
|
//# sourceMappingURL=authCommand.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authCommand.js","sourceRoot":"","sources":["authCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"authCommand.js","sourceRoot":"","sources":["authCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAE9B,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9B,QAAQ,CACN,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM;YAChD,8BAA8B,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO;YACpE,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,wBAAwB,EACpG,mCAAmC,CACpC,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC;IAChD,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnD,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC;IACpC,CAAC;IAED,MAAM,UAAU,GAAG,YAAY;QAC7B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAC;IAEtD,MAAM,aAAa,GAAG,UAAU;QAC9B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,+CAA+C,CAAC;QACrE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAExC,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAErG,QAAQ,CACN,WAAW,UAAU,IAAI;QACzB,kBAAkB,aAAa,MAAM;QACrC,cAAc,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC5C,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;QAC9C,aAAa,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI;QACvD,iBAAiB,YAAY,IAAI,EACjC,6BAA6B,CAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["dashboard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["dashboard.ts"],"names":[],"mappings":"AAIA,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,iBA0BjE"}
|
|
@@ -1,268 +1,25 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
1
|
import { exec } from 'child_process';
|
|
6
|
-
import { spinner } from '@clack/prompts';
|
|
7
2
|
import chalk from 'chalk';
|
|
8
3
|
import { safeNote } from '../utils/markdown.js';
|
|
9
|
-
import { loadAuthConfig, saveAuthConfig, clearAuthConfig, isLoggedIn } from '../utils/auth.js';
|
|
10
|
-
import { firebaseSignIn, firebaseSignUp, FIREBASE_TENANT_ID } from '../utils/firebaseAuth.js';
|
|
11
|
-
import { loadContext } from '../utils/config.js';
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = path.dirname(__filename);
|
|
14
4
|
export async function handleDashboard(options) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
30
|
-
if (req.method === 'OPTIONS') {
|
|
31
|
-
res.writeHead(204);
|
|
32
|
-
res.end();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const parsedUrl = req.url ? new URL(req.url, `http://localhost:${port}`) : new URL('/', `http://localhost:${port}`);
|
|
36
|
-
const pathname = parsedUrl.pathname;
|
|
37
|
-
// JSON API ROUTING
|
|
38
|
-
if (pathname.startsWith('/api/')) {
|
|
39
|
-
handleApiRequest(req, res, pathname);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
// STATIC FILE SERVING
|
|
43
|
-
let reqPath = pathname === '/' ? '/index.html' : pathname;
|
|
44
|
-
const filePath = path.join(webDir, reqPath);
|
|
45
|
-
const mimeTypes = {
|
|
46
|
-
'.html': 'text/html; charset=utf-8',
|
|
47
|
-
'.css': 'text/css; charset=utf-8',
|
|
48
|
-
'.js': 'application/javascript; charset=utf-8',
|
|
49
|
-
'.json': 'application/json',
|
|
50
|
-
'.png': 'image/png',
|
|
51
|
-
'.jpg': 'image/jpeg',
|
|
52
|
-
'.svg': 'image/svg+xml',
|
|
53
|
-
'.ico': 'image/x-icon',
|
|
54
|
-
};
|
|
55
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
56
|
-
const contentType = mimeTypes[ext] || 'text/plain';
|
|
57
|
-
fs.readFile(filePath, (err, content) => {
|
|
5
|
+
const url = 'https://scout.frontterrain.com';
|
|
6
|
+
safeNote(`${chalk.bold.cyan('π Redirecting to FrontTerrain Scout Web Portal...')}\n\n` +
|
|
7
|
+
`URL: ${chalk.bold.underline.yellow(url)}\n\n` +
|
|
8
|
+
`Features:\n` +
|
|
9
|
+
` β’ ${chalk.bold('Sign In / Sign Up')} & Cloud Auth Portal\n` +
|
|
10
|
+
` β’ ${chalk.bold('CLI Session Access Tokens')} (scout login --token)\n` +
|
|
11
|
+
` β’ ${chalk.bold('Live Codebase Fragility & Risk Audits')}\n`, 'π FrontTerrain Scout Web Portal');
|
|
12
|
+
if (options?.open !== false) {
|
|
13
|
+
const openCmd = process.platform === 'win32'
|
|
14
|
+
? `start ${url}`
|
|
15
|
+
: process.platform === 'darwin'
|
|
16
|
+
? `open ${url}`
|
|
17
|
+
: `xdg-open ${url}`;
|
|
18
|
+
exec(openCmd, (err) => {
|
|
58
19
|
if (err) {
|
|
59
|
-
|
|
60
|
-
fs.readFile(indexPath, (fallbackErr, fallbackContent) => {
|
|
61
|
-
if (fallbackErr) {
|
|
62
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
63
|
-
res.end(JSON.stringify({ error: '404 File Not Found' }));
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
67
|
-
res.end(fallbackContent, 'utf-8');
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
73
|
-
res.end(JSON.stringify({ error: `Server Error: ${err.code}` }));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
res.writeHead(200, { 'Content-Type': contentType });
|
|
78
|
-
res.end(content, 'utf-8');
|
|
20
|
+
console.log(chalk.dim(`Note: Open your browser to ${url}`));
|
|
79
21
|
}
|
|
80
22
|
});
|
|
81
|
-
});
|
|
82
|
-
server.listen(port, () => {
|
|
83
|
-
s.stop(chalk.green(`β Scout Dashboard Web Server running!`));
|
|
84
|
-
const url = `http://localhost:${port}`;
|
|
85
|
-
safeNote(`${chalk.bold.cyan('π Scout Web Dashboard is online!')}\n\n` +
|
|
86
|
-
`URL: ${chalk.bold.underline.yellow(url)}\n` +
|
|
87
|
-
`Firebase Tenant: ${chalk.bold.green(FIREBASE_TENANT_ID)}\n` +
|
|
88
|
-
`Local Auth Sync: ${chalk.bold.green('Active (~/.ft/auth.json)')}\n\n` +
|
|
89
|
-
`Features:\n` +
|
|
90
|
-
` β’ ${chalk.bold('Sign In / Sign Up')} synced directly with CLI auth\n` +
|
|
91
|
-
` β’ ${chalk.bold('CLI Session & Token Generator')} (scout login --token)\n` +
|
|
92
|
-
` β’ ${chalk.bold('Live Codebase Scans & Risk Audits')}\n` +
|
|
93
|
-
` β’ ${chalk.bold('Account Profile & AI Engine Settings')}\n\n` +
|
|
94
|
-
`Press ${chalk.cyan('Ctrl+C')} in terminal to stop server.`, 'π FrontTerrain Scout Web Portal');
|
|
95
|
-
if (options?.open !== false) {
|
|
96
|
-
const openCmd = process.platform === 'win32'
|
|
97
|
-
? `start ${url}`
|
|
98
|
-
: process.platform === 'darwin'
|
|
99
|
-
? `open ${url}`
|
|
100
|
-
: `xdg-open ${url}`;
|
|
101
|
-
exec(openCmd, (err) => {
|
|
102
|
-
if (err) {
|
|
103
|
-
console.log(chalk.dim(`Note: Open your browser to ${url}`));
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
server.on('error', (err) => {
|
|
109
|
-
s.stop(chalk.red('β Server failed to start.'));
|
|
110
|
-
if (err.code === 'EADDRINUSE') {
|
|
111
|
-
safeNote(chalk.yellow(`Port ${port} is already in use. Try running with a custom port or kill existing process.`), 'β οΈ Port Collision');
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
safeNote(chalk.red(err.message), 'β Dashboard Error');
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
// Helper to parse JSON POST bodies
|
|
119
|
-
function getRequestBody(req) {
|
|
120
|
-
return new Promise((resolve, reject) => {
|
|
121
|
-
let body = '';
|
|
122
|
-
req.on('data', (chunk) => (body += chunk.toString()));
|
|
123
|
-
req.on('end', () => {
|
|
124
|
-
try {
|
|
125
|
-
resolve(body ? JSON.parse(body) : {});
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
reject(err);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
req.on('error', reject);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
// Handle JSON API Endpoints
|
|
135
|
-
async function handleApiRequest(req, res, pathname) {
|
|
136
|
-
res.setHeader('Content-Type', 'application/json');
|
|
137
|
-
try {
|
|
138
|
-
// GET /api/status - Return local CLI auth status
|
|
139
|
-
if (pathname === '/api/status' && req.method === 'GET') {
|
|
140
|
-
const auth = loadAuthConfig();
|
|
141
|
-
const context = loadContext();
|
|
142
|
-
let scanReport = null;
|
|
143
|
-
const scanPath = path.join(process.cwd(), '.ft', 'scan-report.json');
|
|
144
|
-
if (fs.existsSync(scanPath)) {
|
|
145
|
-
try {
|
|
146
|
-
scanReport = JSON.parse(fs.readFileSync(scanPath, 'utf-8'));
|
|
147
|
-
}
|
|
148
|
-
catch { }
|
|
149
|
-
}
|
|
150
|
-
res.writeHead(200);
|
|
151
|
-
res.end(JSON.stringify({
|
|
152
|
-
success: true,
|
|
153
|
-
isLoggedIn: isLoggedIn(),
|
|
154
|
-
auth,
|
|
155
|
-
tenantId: FIREBASE_TENANT_ID,
|
|
156
|
-
repoPath: process.cwd(),
|
|
157
|
-
hasContext: Boolean(context),
|
|
158
|
-
scanReport,
|
|
159
|
-
}));
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
// POST /api/login - Sign in with Firebase and save auth config to local machine
|
|
163
|
-
if (pathname === '/api/login' && req.method === 'POST') {
|
|
164
|
-
const body = await getRequestBody(req);
|
|
165
|
-
if (!body.email || !body.password) {
|
|
166
|
-
res.writeHead(400);
|
|
167
|
-
res.end(JSON.stringify({ success: false, error: 'Email and password required.' }));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const authRes = await firebaseSignIn(body.email, body.password);
|
|
171
|
-
saveAuthConfig({
|
|
172
|
-
token: authRes.token,
|
|
173
|
-
refreshToken: authRes.refreshToken,
|
|
174
|
-
tenantId: FIREBASE_TENANT_ID,
|
|
175
|
-
user: authRes.user,
|
|
176
|
-
loggedInAt: new Date().toISOString(),
|
|
177
|
-
});
|
|
178
|
-
res.writeHead(200);
|
|
179
|
-
res.end(JSON.stringify({ success: true, auth: authRes }));
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
// POST /api/signup - Sign up with Firebase and save auth config
|
|
183
|
-
if (pathname === '/api/signup' && req.method === 'POST') {
|
|
184
|
-
const body = await getRequestBody(req);
|
|
185
|
-
if (!body.name || !body.email || !body.password) {
|
|
186
|
-
res.writeHead(400);
|
|
187
|
-
res.end(JSON.stringify({ success: false, error: 'Name, email, and password required.' }));
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const authRes = await firebaseSignUp(body.name, body.email, body.password);
|
|
191
|
-
saveAuthConfig({
|
|
192
|
-
token: authRes.token,
|
|
193
|
-
refreshToken: authRes.refreshToken,
|
|
194
|
-
tenantId: FIREBASE_TENANT_ID,
|
|
195
|
-
user: authRes.user,
|
|
196
|
-
loggedInAt: new Date().toISOString(),
|
|
197
|
-
});
|
|
198
|
-
res.writeHead(200);
|
|
199
|
-
res.end(JSON.stringify({ success: true, auth: authRes }));
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
// POST /api/save-auth - Directly save auth state (e.g. from token or client login)
|
|
203
|
-
if (pathname === '/api/save-auth' && req.method === 'POST') {
|
|
204
|
-
const body = await getRequestBody(req);
|
|
205
|
-
if (body.user && body.token) {
|
|
206
|
-
saveAuthConfig({
|
|
207
|
-
token: body.token,
|
|
208
|
-
refreshToken: body.refreshToken || null,
|
|
209
|
-
tenantId: FIREBASE_TENANT_ID,
|
|
210
|
-
user: body.user,
|
|
211
|
-
loggedInAt: new Date().toISOString(),
|
|
212
|
-
});
|
|
213
|
-
res.writeHead(200);
|
|
214
|
-
res.end(JSON.stringify({ success: true }));
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
res.writeHead(400);
|
|
218
|
-
res.end(JSON.stringify({ success: false, error: 'Invalid user or token provided.' }));
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
// POST /api/logout - Clear auth config on machine
|
|
222
|
-
if (pathname === '/api/logout' && req.method === 'POST') {
|
|
223
|
-
clearAuthConfig();
|
|
224
|
-
res.writeHead(200);
|
|
225
|
-
res.end(JSON.stringify({ success: true }));
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
// POST /api/cli/exec - Execute Scout CLI command directly from Web Terminal
|
|
229
|
-
if (pathname === '/api/cli/exec' && req.method === 'POST') {
|
|
230
|
-
const body = await getRequestBody(req);
|
|
231
|
-
const rawCommand = (body.command || '').trim();
|
|
232
|
-
if (!rawCommand) {
|
|
233
|
-
res.writeHead(400);
|
|
234
|
-
res.end(JSON.stringify({ success: false, error: 'Command string is required.' }));
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
// Strip scout/ft prefix if user typed it
|
|
238
|
-
const argsStr = rawCommand.replace(/^(scout|ft)\s*/i, '').trim();
|
|
239
|
-
const ftBinPath = path.resolve(__dirname, '../../ft.js');
|
|
240
|
-
const childEnv = { ...process.env, FORCE_COLOR: '1' };
|
|
241
|
-
exec(`node "${ftBinPath}" ${argsStr}`, { cwd: process.cwd(), timeout: 60000, env: childEnv }, (err, stdout, stderr) => {
|
|
242
|
-
let outputText = (stdout || '').trim();
|
|
243
|
-
if (stderr && stderr.trim()) {
|
|
244
|
-
outputText = outputText ? `${outputText}\n${stderr.trim()}` : stderr.trim();
|
|
245
|
-
}
|
|
246
|
-
if (!outputText && err) {
|
|
247
|
-
outputText = `Error executing command: ${err.message}`;
|
|
248
|
-
}
|
|
249
|
-
res.writeHead(200);
|
|
250
|
-
res.end(JSON.stringify({
|
|
251
|
-
success: !err || err.code === 0,
|
|
252
|
-
command: rawCommand,
|
|
253
|
-
output: outputText || 'Command executed successfully (no output).',
|
|
254
|
-
exitCode: err ? (err.code || 1) : 0,
|
|
255
|
-
}));
|
|
256
|
-
});
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
// Unmatched API endpoint
|
|
260
|
-
res.writeHead(404);
|
|
261
|
-
res.end(JSON.stringify({ success: false, error: 'API endpoint not found.' }));
|
|
262
|
-
}
|
|
263
|
-
catch (error) {
|
|
264
|
-
res.writeHead(500);
|
|
265
|
-
res.end(JSON.stringify({ success: false, error: error?.message || 'Server error occurred.' }));
|
|
266
23
|
}
|
|
267
24
|
}
|
|
268
25
|
//# sourceMappingURL=dashboard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["dashboard.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA4B;IAChE,MAAM,GAAG,GAAG,gCAAgC,CAAC;IAE7C,QAAQ,CACN,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oDAAoD,CAAC,MAAM;QAC9E,QAAQ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;QAC9C,aAAa;QACb,MAAM,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,wBAAwB;QAC7D,MAAM,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,0BAA0B;QACvE,MAAM,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,IAAI,EAC7D,kCAAkC,CACnC,CAAC;IAEF,IAAI,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;QAC5B,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC1B,CAAC,CAAC,SAAS,GAAG,EAAE;YAChB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;gBAC/B,CAAC,CAAC,QAAQ,GAAG,EAAE;gBACf,CAAC,CAAC,YAAY,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACpB,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,GAAG,EAAE,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["init.ts"],"names":[],"mappings":"AAuOA,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,iBAiYjJ"}
|
package/bin/src/commands/init.js
CHANGED
|
@@ -1,13 +1,99 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
-
import { spinner, note, password, isCancel, text, select } from '@clack/prompts';
|
|
4
|
+
import { spinner, note, password, isCancel, text, select, confirm } from '@clack/prompts';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { simpleGit } from 'simple-git';
|
|
7
7
|
import { generateRepoSummary, askRepoQuestion } from '../engine/llm.js';
|
|
8
|
-
import { saveContext, loadContext } from '../utils/config.js';
|
|
8
|
+
import { saveContext, loadContext, saveScanReport } from '../utils/config.js';
|
|
9
9
|
import { renderMarkdown, formatInlineMarkdown, safeNote } from '../utils/markdown.js';
|
|
10
10
|
import { normalizeLanguage, getLanguageInstruction } from '../utils/language.js';
|
|
11
|
+
function detectPackageManager(dir) {
|
|
12
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml')))
|
|
13
|
+
return 'pnpm';
|
|
14
|
+
if (fs.existsSync(path.join(dir, 'yarn.lock')))
|
|
15
|
+
return 'yarn';
|
|
16
|
+
if (fs.existsSync(path.join(dir, 'bun.lockb')) || fs.existsSync(path.join(dir, 'bun.lock')))
|
|
17
|
+
return 'bun';
|
|
18
|
+
if (fs.existsSync(path.join(dir, 'package-lock.json')))
|
|
19
|
+
return 'npm';
|
|
20
|
+
if (fs.existsSync(path.join(dir, 'Cargo.lock')))
|
|
21
|
+
return 'cargo';
|
|
22
|
+
if (fs.existsSync(path.join(dir, 'poetry.lock')))
|
|
23
|
+
return 'poetry';
|
|
24
|
+
if (fs.existsSync(path.join(dir, 'Pipfile')))
|
|
25
|
+
return 'pipenv';
|
|
26
|
+
if (fs.existsSync(path.join(dir, 'build.gradle')) || fs.existsSync(path.join(dir, 'gradlew')))
|
|
27
|
+
return 'gradle';
|
|
28
|
+
return 'npm';
|
|
29
|
+
}
|
|
30
|
+
function detectWorkspaces(dir) {
|
|
31
|
+
const workspaces = [];
|
|
32
|
+
const checks = [
|
|
33
|
+
{ file: 'pnpm-workspace.yaml', type: 'pnpm Workspaces' },
|
|
34
|
+
{ file: 'turbo.json', type: 'Turborepo' },
|
|
35
|
+
{ file: 'lerna.json', type: 'Lerna Monorepo' },
|
|
36
|
+
{ file: 'nx.json', type: 'Nx Workspace' },
|
|
37
|
+
];
|
|
38
|
+
for (const c of checks) {
|
|
39
|
+
if (fs.existsSync(path.join(dir, c.file))) {
|
|
40
|
+
workspaces.push(c.type);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const pkgJsonPath = path.join(dir, 'package.json');
|
|
44
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
45
|
+
try {
|
|
46
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
47
|
+
if (pkg.workspaces) {
|
|
48
|
+
if (Array.isArray(pkg.workspaces)) {
|
|
49
|
+
pkg.workspaces.forEach((w) => workspaces.push(`package (${w})`));
|
|
50
|
+
}
|
|
51
|
+
else if (pkg.workspaces.packages && Array.isArray(pkg.workspaces.packages)) {
|
|
52
|
+
pkg.workspaces.packages.forEach((w) => workspaces.push(`package (${w})`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
}
|
|
58
|
+
// Check common subdirectories
|
|
59
|
+
const subDirs = ['apps', 'packages', 'services', 'modules', 'libs'];
|
|
60
|
+
for (const sub of subDirs) {
|
|
61
|
+
const subPath = path.join(dir, sub);
|
|
62
|
+
if (fs.existsSync(subPath) && fs.statSync(subPath).isDirectory()) {
|
|
63
|
+
try {
|
|
64
|
+
const contents = fs.readdirSync(subPath).filter((f) => {
|
|
65
|
+
const p = path.join(subPath, f);
|
|
66
|
+
return fs.statSync(p).isDirectory() && !f.startsWith('.');
|
|
67
|
+
});
|
|
68
|
+
if (contents.length > 0) {
|
|
69
|
+
workspaces.push(`${sub}/ (${contents.length} packages: ${contents.slice(0, 3).join(', ')}${contents.length > 3 ? '...' : ''})`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch { }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const isMonorepo = workspaces.length > 0;
|
|
76
|
+
return { isMonorepo, workspaces: Array.from(new Set(workspaces)) };
|
|
77
|
+
}
|
|
78
|
+
async function bootstrapEnvironmentFile(dir) {
|
|
79
|
+
const envPath = path.join(dir, '.env');
|
|
80
|
+
if (fs.existsSync(envPath))
|
|
81
|
+
return false;
|
|
82
|
+
const exampleCandidates = ['.env.example', '.env.template', '.env.local.example', '.env.sample', 'env.example'];
|
|
83
|
+
for (const candidate of exampleCandidates) {
|
|
84
|
+
const examplePath = path.join(dir, candidate);
|
|
85
|
+
if (fs.existsSync(examplePath)) {
|
|
86
|
+
try {
|
|
87
|
+
const content = fs.readFileSync(examplePath, 'utf-8');
|
|
88
|
+
fs.writeFileSync(envPath, content);
|
|
89
|
+
note(chalk.green(`Auto-created ${chalk.bold('.env')} from ${chalk.bold(candidate)}.\nPlease update any API keys or secrets in .env before running services.`), 'β‘ Environment Auto-Setup');
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
11
97
|
function extractNpmPackageName(target) {
|
|
12
98
|
if (target.startsWith('npm:')) {
|
|
13
99
|
return target.slice(4).trim();
|
|
@@ -282,7 +368,37 @@ export async function handleInit(repoUrl, options) {
|
|
|
282
368
|
}
|
|
283
369
|
}
|
|
284
370
|
}
|
|
371
|
+
const pkgManager = detectPackageManager(targetDir);
|
|
372
|
+
const workspaceInfo = detectWorkspaces(targetDir);
|
|
373
|
+
await bootstrapEnvironmentFile(targetDir);
|
|
285
374
|
s.start(`Analyzing repository at ${chalk.cyan(targetDir)}${langDisplay ? ` (Language: ${chalk.bold.yellow(langDisplay)})` : ''}...`);
|
|
375
|
+
// Perform quick pre-flight fragility scan for .ft/scan-report.json
|
|
376
|
+
try {
|
|
377
|
+
const git = simpleGit(targetDir);
|
|
378
|
+
const log = await git.log({ maxCount: 100 });
|
|
379
|
+
const fileStats = {};
|
|
380
|
+
for (const commit of log.all) {
|
|
381
|
+
if (/fix|bug|hotfix|patch/i.test(commit.message)) {
|
|
382
|
+
try {
|
|
383
|
+
const diff = await git.show(['--name-only', '--oneline', commit.hash]);
|
|
384
|
+
const files = diff.split('\n').slice(1).filter(Boolean);
|
|
385
|
+
for (const f of files) {
|
|
386
|
+
fileStats[f] = (fileStats[f] || 0) + 1;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch { }
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const scanReport = Object.entries(fileStats).map(([file, hotfixes]) => ({
|
|
393
|
+
file,
|
|
394
|
+
hotfixes,
|
|
395
|
+
riskLevel: hotfixes >= 3 ? 'HIGH' : hotfixes >= 1 ? 'MEDIUM' : 'LOW',
|
|
396
|
+
}));
|
|
397
|
+
if (scanReport.length > 0) {
|
|
398
|
+
saveScanReport(scanReport);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
catch { }
|
|
286
402
|
// Scan file tree up to 2 levels deep
|
|
287
403
|
const getFiles = (dir, depth = 2) => {
|
|
288
404
|
let results = [];
|
|
@@ -338,6 +454,10 @@ export async function handleInit(repoUrl, options) {
|
|
|
338
454
|
readOrder: aiInsight.readOrder,
|
|
339
455
|
createdAt: new Date().toISOString(),
|
|
340
456
|
language: targetLang,
|
|
457
|
+
packageManager: pkgManager,
|
|
458
|
+
isMonorepo: workspaceInfo.isMonorepo,
|
|
459
|
+
workspaces: workspaceInfo.workspaces,
|
|
460
|
+
architectureDiagram: aiInsight.architectureDiagram,
|
|
341
461
|
});
|
|
342
462
|
}
|
|
343
463
|
s.stop('Repository analysis complete.');
|
|
@@ -355,12 +475,20 @@ export async function handleInit(repoUrl, options) {
|
|
|
355
475
|
'package.json -> Core manifest defining build targets and dependency graph',
|
|
356
476
|
'src/index.ts -> Primary router establishing CLI hooks and command workflow'
|
|
357
477
|
];
|
|
478
|
+
// Format workspace & package manager details
|
|
479
|
+
const workspaceStr = workspaceInfo.isMonorepo
|
|
480
|
+
? `\nWorkspace Type: ${chalk.bold.magenta('Monorepo')} (${workspaceInfo.workspaces.join(', ')})`
|
|
481
|
+
: '';
|
|
482
|
+
const archDiagramStr = aiInsight.architectureDiagram
|
|
483
|
+
? `\n\n${chalk.bold.blue('πΊοΈ Subsystem Architecture Flow:')}\n${chalk.dim(aiInsight.architectureDiagram)}`
|
|
484
|
+
: '';
|
|
358
485
|
// Print repository summary
|
|
359
486
|
safeNote(`Project Name: ${chalk.bold.green(projectName)}
|
|
360
487
|
Location: ${chalk.dim(targetDir)}${langDisplay ? `\nLanguage: ${chalk.bold.yellow(langDisplay)}` : ''}
|
|
488
|
+
Package Manager: ${chalk.bold.cyan(pkgManager.toUpperCase())}${workspaceStr}
|
|
361
489
|
|
|
362
490
|
${chalk.bold.magenta('π Architectural Executive Summary & Stack:')}
|
|
363
|
-
${renderMarkdown(aiInsight.summary)}
|
|
491
|
+
${renderMarkdown(aiInsight.summary)}${archDiagramStr}
|
|
364
492
|
|
|
365
493
|
${chalk.bold.cyan('π Main Entry Point:')}
|
|
366
494
|
${chalk.cyan(aiInsight.entryPoint)}
|