Skip to content

Commit 6ab5a1e

Browse files
Add files via upload
1 parent 4058b3a commit 6ab5a1e

37 files changed

Lines changed: 11585 additions & 0 deletions
50.4 KB
Binary file not shown.

agent/agent.py

Lines changed: 940 additions & 0 deletions
Large diffs are not rendered by default.

agent/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
flask>=3.0.0
2+
flask-cors>=4.0.0
3+
requests>=2.31.0
4+
llama-cpp-python>=0.2.90

dist/flint-logo.png

3.33 MB
Loading

dist/index.html

Lines changed: 276 additions & 0 deletions
Large diffs are not rendered by default.

electron/main.cjs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Flint — Electron Desktop Wrapper
2+
// .cjs = guaranteed CommonJS regardless of any "type":"module"
3+
4+
const { app, BrowserWindow, Menu, shell } = require('electron');
5+
const path = require('path');
6+
const fs = require('fs');
7+
const { spawn } = require('child_process');
8+
9+
let mainWindow = null;
10+
let agentProcess = null;
11+
12+
const APP_DIR = __dirname;
13+
const DIST_FILE = path.join(APP_DIR, 'dist', 'index.html');
14+
const ICON_FILE = path.join(APP_DIR, 'icon.png');
15+
16+
// ── Start Python AI Agent ──────────────────────────────────
17+
function startAgent() {
18+
const agentDir = path.join(APP_DIR, 'agent');
19+
const agentScript = path.join(agentDir, 'agent.py');
20+
21+
if (!fs.existsSync(agentScript)) {
22+
console.log('[Flint] No agent found — AI will use browser fallback');
23+
return;
24+
}
25+
26+
console.log('[Flint] Starting Python AI agent...');
27+
28+
// Try python3 first, then python
29+
const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
30+
31+
agentProcess = spawn(pythonCmd, [agentScript], {
32+
cwd: agentDir,
33+
env: { ...process.env },
34+
stdio: ['pipe', 'pipe', 'pipe'],
35+
detached: false,
36+
});
37+
38+
agentProcess.stdout.on('data', (data) => {
39+
const msg = data.toString().trim();
40+
if (msg) console.log('[Flint Agent]', msg);
41+
});
42+
43+
agentProcess.stderr.on('data', (data) => {
44+
const msg = data.toString().trim();
45+
if (msg && !msg.includes('DeprecationWarning') && !msg.includes('WARNING')) {
46+
console.log('[Flint Agent]', msg);
47+
}
48+
});
49+
50+
agentProcess.on('error', (err) => {
51+
console.log('[Flint] Agent failed to start:', err.message);
52+
console.log('[Flint] Install Python + Flask: pip3 install flask flask-cors requests');
53+
});
54+
55+
agentProcess.on('exit', (code) => {
56+
console.log('[Flint] Agent stopped (code', code, ')');
57+
agentProcess = null;
58+
});
59+
}
60+
61+
function stopAgent() {
62+
if (agentProcess) {
63+
console.log('[Flint] Stopping agent...');
64+
agentProcess.kill('SIGTERM');
65+
agentProcess = null;
66+
}
67+
}
68+
69+
// ── Create Window ──────────────────────────────────────────
70+
71+
function createWindow() {
72+
if (!fs.existsSync(DIST_FILE)) {
73+
console.error('[Flint] ERROR: dist/index.html not found at ' + DIST_FILE);
74+
console.error('[Flint] Run: bash install.sh');
75+
app.quit();
76+
return;
77+
}
78+
79+
mainWindow = new BrowserWindow({
80+
width: 1400,
81+
height: 900,
82+
minWidth: 800,
83+
minHeight: 600,
84+
title: 'Flint',
85+
backgroundColor: '#0a0a0a',
86+
icon: fs.existsSync(ICON_FILE) ? ICON_FILE : undefined,
87+
autoHideMenuBar: true,
88+
show: false,
89+
webPreferences: {
90+
nodeIntegration: false,
91+
contextIsolation: true,
92+
sandbox: true,
93+
},
94+
});
95+
96+
Menu.setApplicationMenu(null);
97+
98+
mainWindow.loadFile(DIST_FILE).then(() => {
99+
console.log('[Flint] Loaded successfully');
100+
}).catch(err => {
101+
console.error('[Flint] Failed to load:', err.message);
102+
});
103+
104+
mainWindow.once('ready-to-show', () => {
105+
if (mainWindow) {
106+
mainWindow.show();
107+
console.log('[Flint] Window displayed');
108+
}
109+
});
110+
111+
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
112+
if (url.startsWith('http://localhost') || url.startsWith('http://127.0.0.1')) {
113+
return { action: 'allow' };
114+
}
115+
shell.openExternal(url);
116+
return { action: 'deny' };
117+
});
118+
119+
mainWindow.on('closed', () => {
120+
mainWindow = null;
121+
});
122+
}
123+
124+
// ── App Lifecycle ──────────────────────────────────────────
125+
126+
const gotLock = app.requestSingleInstanceLock();
127+
if (!gotLock) {
128+
app.quit();
129+
} else {
130+
app.on('second-instance', () => {
131+
if (mainWindow) {
132+
if (mainWindow.isMinimized()) mainWindow.restore();
133+
mainWindow.focus();
134+
}
135+
});
136+
137+
app.whenReady().then(() => {
138+
// Start Python agent before creating window
139+
startAgent();
140+
createWindow();
141+
console.log('[Flint] App ready — desktop mode');
142+
});
143+
144+
app.on('window-all-closed', () => {
145+
stopAgent();
146+
app.quit();
147+
});
148+
149+
app.on('before-quit', () => {
150+
stopAgent();
151+
});
152+
153+
app.on('activate', () => {
154+
if (mainWindow === null) createWindow();
155+
});
156+
}

index.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self' http://localhost:* http://127.0.0.1:* https://en.wikipedia.org https://*.wikipedia.org; font-src 'self' data:;" />
7+
<meta name="description" content="Flint — A secure, local-first knowledge base. Your notes, your data, your control." />
8+
<title>Flint</title>
9+
<link rel="icon" href="/flint-logo.png" />
10+
</head>
11+
<body>
12+
<div id="root"></div>
13+
<script type="module" src="/src/main.tsx"></script>
14+
</body>
15+
</html>

0 commit comments

Comments
 (0)