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.
Files changed (42) hide show
  1. package/.firebase/hosting.d2Vi.cache +4 -3
  2. package/bin/src/commands/authCommand.d.ts.map +1 -1
  3. package/bin/src/commands/authCommand.js +20 -9
  4. package/bin/src/commands/authCommand.js.map +1 -1
  5. package/bin/src/commands/dashboard.d.ts.map +1 -1
  6. package/bin/src/commands/dashboard.js +15 -258
  7. package/bin/src/commands/dashboard.js.map +1 -1
  8. package/bin/src/commands/init.d.ts.map +1 -1
  9. package/bin/src/commands/init.js +131 -3
  10. package/bin/src/commands/init.js.map +1 -1
  11. package/bin/src/commands/login.d.ts.map +1 -1
  12. package/bin/src/commands/login.js +108 -12
  13. package/bin/src/commands/login.js.map +1 -1
  14. package/bin/src/commands/risky.d.ts.map +1 -1
  15. package/bin/src/commands/risky.js +168 -10
  16. package/bin/src/commands/risky.js.map +1 -1
  17. package/bin/src/commands/signup.d.ts.map +1 -1
  18. package/bin/src/commands/signup.js +29 -11
  19. package/bin/src/commands/signup.js.map +1 -1
  20. package/bin/src/discovery/messages.js +1 -1
  21. package/bin/src/discovery/messages.js.map +1 -1
  22. package/bin/src/engine/llm.d.ts.map +1 -1
  23. package/bin/src/engine/llm.js +49 -2
  24. package/bin/src/engine/llm.js.map +1 -1
  25. package/bin/src/index.js +17 -31
  26. package/bin/src/index.js.map +1 -1
  27. package/bin/src/utils/auth.d.ts.map +1 -1
  28. package/bin/src/utils/auth.js +2 -0
  29. package/bin/src/utils/auth.js.map +1 -1
  30. package/bin/src/utils/branding.js +1 -1
  31. package/bin/src/utils/config.d.ts.map +1 -1
  32. package/bin/src/utils/config.js.map +1 -1
  33. package/bin/src/utils/firebaseAuth.d.ts.map +1 -1
  34. package/bin/src/utils/firebaseAuth.js +0 -2
  35. package/bin/src/utils/firebaseAuth.js.map +1 -1
  36. package/bin/src/utils/holoseneAuth.d.ts.map +1 -0
  37. package/bin/src/utils/holoseneAuth.js +179 -0
  38. package/bin/src/utils/holoseneAuth.js.map +1 -0
  39. package/package.json +2 -2
  40. package/web/app.js +258 -22
  41. package/web/favicon.svg +39 -0
  42. package/web/styles.css +43 -0
@@ -1,3 +1,4 @@
1
- app.js,1786107277133,5eb48a698b2bd6954b1b724c52fbb286ea13061677f8ca1099af4240f814fe59
2
- styles.css,1786107246596,7dfc32e7809e571192c704f6ff64ee707f989afce82401ac4e4de7faa18ce31a
3
- index.html,1786107231618,764067a5c6244694891ac2ef7cf4f5ea5c2a50a965edb86c4b5066b5e834998b
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":"AAKA,wBAAsB,gBAAgB,kBAgCrC"}
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, FIREBASE_TENANT_ID, FIREBASE_PROJECT_ID } from '../utils/firebaseAuth.js';
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('ft login')} to sign in or ${chalk.cyan('ft signup')} to create an account.`, 'πŸ” FrontTerrain Firebase Auth Status');
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 verification = await firebaseLookupToken(auth.token);
15
- const liveStatus = verification.valid
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 tokenMasked = auth.token.length > 14
19
- ? `${auth.token.substring(0, 10)}...${auth.token.substring(auth.token.length - 4)}`
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\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,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExG,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,oBAAoB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,cAAc,mBAAmB,KAAK;YAC/F,8BAA8B,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO;YACpE,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,wBAAwB,EAC9F,sCAAsC,CACvC,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK;QACnC,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,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE;QACxC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE;QACnF,CAAC,CAAC,KAAK,CAAC;IAEV,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,MAAM;QAC3B,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,iBAAiB,YAAY,IAAI,EACjC,6BAA6B,CAC9B,CAAC;AACJ,CAAC"}
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":"AAeA,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,iBA4HhF"}
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 port = options?.port || 3456;
16
- const s = spinner();
17
- // Locate the web directory relative to CLI root
18
- const webDir = path.resolve(__dirname, '../../../web');
19
- const indexPath = path.join(webDir, 'index.html');
20
- if (!fs.existsSync(indexPath)) {
21
- safeNote(chalk.red(`Web dashboard assets not found at ${webDir}.\nPlease ensure the web UI files exist.`), '⚠️ Scout Web Error');
22
- return;
23
- }
24
- s.start(`Launching FrontTerrain Scout Web Dashboard server...`);
25
- const server = http.createServer((req, res) => {
26
- // Enable CORS for local cross-origin calls
27
- res.setHeader('Access-Control-Allow-Origin', '*');
28
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
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
- if (err.code === 'ENOENT') {
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":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA2C;IAC/E,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;IACnC,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;IAEpB,gDAAgD;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAElD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,QAAQ,CACN,KAAK,CAAC,GAAG,CAAC,qCAAqC,MAAM,0CAA0C,CAAC,EAChG,oBAAoB,CACrB,CAAC;QACF,OAAO;IACT,CAAC;IAED,CAAC,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,2CAA2C;QAC3C,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;QACpE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,6BAA6B,CAAC,CAAC;QAE7E,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;QACpH,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;QAEpC,mBAAmB;QACnB,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,sBAAsB;QACtB,IAAI,OAAO,GAAG,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE5C,MAAM,SAAS,GAA2B;YACxC,OAAO,EAAE,0BAA0B;YACnC,MAAM,EAAE,yBAAyB;YACjC,KAAK,EAAE,uCAAuC;YAC9C,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,eAAe;YACvB,MAAM,EAAE,cAAc;SACvB,CAAC;QAEF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC;QAEnD,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACrC,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1B,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,eAAe,EAAE,EAAE;wBACtD,IAAI,WAAW,EAAE,CAAC;4BAChB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;4BAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC;wBAC3D,CAAC;6BAAM,CAAC;4BACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;4BACnE,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;wBACpC,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACvB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,oBAAoB,IAAI,EAAE,CAAC;QAEvC,QAAQ,CACN,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,CAAC,MAAM;YAC7D,QAAQ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;YAC5C,oBAAoB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI;YAC5D,oBAAoB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,MAAM;YACtE,aAAa;YACb,MAAM,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,kCAAkC;YACvE,MAAM,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,0BAA0B;YAC3E,MAAM,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,IAAI;YACzD,MAAM,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,MAAM;YAC9D,SAAS,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,8BAA8B,EAC3D,kCAAkC,CACnC,CAAC;QAEF,IAAI,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;YAC5B,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC1B,CAAC,CAAC,SAAS,GAAG,EAAE;gBAChB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;oBAC/B,CAAC,CAAC,QAAQ,GAAG,EAAE;oBACf,CAAC,CAAC,YAAY,GAAG,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACpB,IAAI,GAAG,EAAE,CAAC;oBACR,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAQ,EAAE,EAAE;QAC9B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC;QAC/C,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC9B,QAAQ,CACN,KAAK,CAAC,MAAM,CAAC,QAAQ,IAAI,8EAA8E,CAAC,EACxG,mBAAmB,CACpB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mCAAmC;AACnC,SAAS,cAAc,CAAC,GAAyB;IAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,4BAA4B;AAC5B,KAAK,UAAU,gBAAgB,CAAC,GAAyB,EAAE,GAAwB,EAAE,QAAgB;IACnG,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,iDAAiD;QACjD,IAAI,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACvD,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;YAC9B,IAAI,UAAU,GAAG,IAAI,CAAC;YAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC;YACrE,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC9D,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;gBACb,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,UAAU,EAAE;gBACxB,IAAI;gBACJ,QAAQ,EAAE,kBAAkB;gBAC5B,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE;gBACvB,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC;gBAC5B,UAAU;aACX,CAAC,CACH,CAAC;YACF,OAAO;QACT,CAAC;QAED,gFAAgF;QAChF,IAAI,QAAQ,KAAK,YAAY,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACvD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC,CAAC;gBACnF,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChE,cAAc,CAAC;gBACb,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC,CAAC;YAEH,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,gEAAgE;QAChE,IAAI,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC,CAAC,CAAC;gBAC1F,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3E,cAAc,CAAC;gBACb,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC,CAAC;YAEH,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,mFAAmF;QACnF,IAAI,QAAQ,KAAK,gBAAgB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3D,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC5B,cAAc,CAAC;oBACb,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;oBACvC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACrC,CAAC,CAAC;gBACH,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YACD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QAED,kDAAkD;QAClD,IAAI,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACxD,eAAe,EAAE,CAAC;YAClB,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,4EAA4E;QAC5E,IAAI,QAAQ,KAAK,eAAe,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1D,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YACvC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAE/C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC,CAAC,CAAC;gBAClF,OAAO;YACT,CAAC;YAED,yCAAyC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACjE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YAEzD,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC;YACtD,IAAI,CAAC,SAAS,SAAS,KAAK,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;gBACpH,IAAI,UAAU,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC5B,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC9E,CAAC;gBACD,IAAI,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;oBACvB,UAAU,GAAG,4BAA4B,GAAG,CAAC,OAAO,EAAE,CAAC;gBACzD,CAAC;gBAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;oBACb,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAC/B,OAAO,EAAE,UAAU;oBACnB,MAAM,EAAE,UAAU,IAAI,4CAA4C;oBAClE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACpC,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,yBAAyB;QACzB,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,IAAI,wBAAwB,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC;AACH,CAAC"}
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":"AAmJA,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,iBAqVjJ"}
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"}
@@ -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)}