fanluc 2.0.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/dist/assets/{abnfDiagram-O67JEVCF-hiYMdxpV.js → abnfDiagram-O67JEVCF-Di2iDQfl.js} +1 -1
- package/dist/assets/{arc-DokRg_wy.js → arc-wXq_yD5s.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-UzHYe9Bx.js → architectureDiagram-NJMV4G6O-CTXbg-3W.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-DqM5UILT.js → blockDiagram-BEXU5L5S-DSDoL3RP.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-Cxkdm7sV.js → c4Diagram-YGBWAQC7-3sFM3iyw.js} +1 -1
- package/dist/assets/channel-atnI5OIR.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-Nl4zmLlG.js → chunk-2Q5K7J3B-DUOKiJNI.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-BCol78O2.js → chunk-3FUC2YCW-ablWb8_c.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-1u4YRv2Y.js → chunk-5VM5RSS4-qmlSVZ_1.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-BG9YIV2h.js → chunk-GTNCS2PH-PLlC7cNS.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BTKfkJAH.js → chunk-GWA4HPMP-DK-1a6YJ.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DCjElfA7.js → chunk-JWPE2WC7-D9zynFKs.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-QoJORlVn.js → chunk-NETBCI7D-BvzPMYyE.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-Da-T8ct9.js → chunk-WEXAMYUT-CzcfZFWB.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-CLu69Uei.js → chunk-XXDRQBXY-DznN-rwG.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-DIXavbI9.js → classDiagram-v2-NBCMYWYE-D4jem0hV.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-DuWclG8-.js → cose-bilkent-JH36ORCC-VALsUQJS.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-D2CG5-xd.js → cynefin-OW5HDTMX-DK77QSI8.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-goI7_Qfg.js → cynefinDiagram-VND7K2PF-CdYXfGNR.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-BmOaZ0cm.js → dagre-6A5THRUB-DeeUQzDV.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-DjDJFMw3.js → diagram-22UHCM2B-B9shZ914.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-J6z81NH3.js → diagram-3UASUU5V-gSHvaXBI.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-B1MPU8ai.js → diagram-ATOU4E4O-BrCI5HzS.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-X5Uss0Yv.js → diagram-CDSNMT55-XtVlMRq0.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-CRDqfYy1.js → diagram-MLGK6HIB-BVa6KsvA.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-bhJtyiOq.js → diagram-MPIPVDR6-C8P23P2T.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-Dn1mZAV8.js → ebnfDiagram-ZINNZB2B-BrooaQj5.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-C93BlBEU.js → elk-276RUBZZ-B-qiKlkF.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-PuzjAvhD.js → erDiagram-OPXOYQCR-CL1bp2Mf.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-oRhFgO0p.js → flowDiagram-KWPJA3E3-BMQvaQ-5.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-DKiU1XjU.js → ganttDiagram-FUAMR5RP-PLnTGRI8.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-CWBMI0vb.js → gitGraphDiagram-X574FWY7-CiTN3Joc.js} +1 -1
- package/dist/assets/index-BEKLwzQT.css +1 -0
- package/dist/assets/index-C8gDJtDK.js +2841 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-C5Hd4Afz.js → infoDiagram-VRGFBTTK-ComkS_96.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-BdD6ulRK.js → ishikawaDiagram-OU5B5YK6-D-dNoDFJ.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-CzT-uvks.js → journeyDiagram-ZHPQQLJL-BMm9BQM8.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BkrazFMR.js → kanban-definition-PNTS6WVX-D5If-l_D.js} +1 -1
- package/dist/assets/{linear-B0wSM1Dr.js → linear-DXAHb0Ag.js} +1 -1
- package/dist/assets/{mindmap-definition-NLK3R4M7-Df1Acqkf.js → mindmap-definition-NLK3R4M7-CIdwCXTJ.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-DK_F7h_0.js → pegDiagram-GJSIUBJH-MY7FoVQh.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-BMXyNb9R.js → pieDiagram-5QR66LMP-C7lWWAtM.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-Dfu7Z8so.js → quadrantDiagram-O4NWA36T-jHqCwvi8.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-CfnBD-aQ.js → railroadDiagram-XR7U4H2S-BwoIA8Ln.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-DrvsZJPP.js → requirementDiagram-PLB6GJNP-Cw8w0Rwb.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-DvdVDpT1.js → sankeyDiagram-IPEJSGJF-DTRo1Yxy.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-D1UTrvZH.js → sequenceDiagram-PO4LG4MO-DqZddXsc.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-CJrOBcai.js → sizeCapture-INFHLROL-BAEQ4XP5.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-CX8VmtqD.js → stateDiagram-v2-GCMORJYK-CYB4CouD.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-DUWmhiK6.js → swimlanes-2SLR337P-Dw53LU13.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-Dzkep6h_.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-CBovVdOU.js → timeline-definition-EJHVYXUP-Chk-unGo.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-LD5N5BAG.js → usecaseDiagram-POWQR4AR-D_JpD-4l.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-DdwfzB3A.js → vennDiagram-UO4OBE2U-BnPO8gk8.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-BMHK4bav.js → wardleyDiagram-VNRHLVJA-CD0z1l8R.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-q1BNzMC-.js → xychartDiagram-PMCCYNJV-CHEqj1Pe.js} +1 -1
- package/dist/cli.js +52 -57
- package/dist/index.html +4 -4
- package/dist/server.cjs +2144 -841
- package/dist/server.cjs.map +4 -4
- package/dist/tui.js +3220 -3310
- package/docs/fanluc_ui.md +120 -40
- package/docs/guide-connect.md +233 -4
- package/docs/run-cmd-security.md +26 -0
- package/index.html +2 -2
- package/mcp.json +3 -0
- package/package.json +88 -92
- package/searxng/docker-compose.yml +3 -3
- package/vite.config.ts +2 -2
- package/dist/assets/channel-SPfNTvmj.js +0 -1
- package/dist/assets/index-BylpTP-E.css +0 -1
- package/dist/assets/index-DcpVteR3.js +0 -3237
- package/dist/assets/permissionHelper--88tJJlz.js +0 -3
- package/dist/assets/swimlanesDiagram-TC7HE7FX-DMQy1553.js +0 -8
package/dist/cli.js
CHANGED
|
@@ -11,22 +11,21 @@ import path from "path";
|
|
|
11
11
|
import fs from "fs";
|
|
12
12
|
import os from "os";
|
|
13
13
|
var PERMISSION_DESCRIPTIONS = {
|
|
14
|
-
ask: "
|
|
15
|
-
autoEdit: "
|
|
16
|
-
readOnly: "
|
|
14
|
+
ask: "Ask every time before writing files or running shell commands",
|
|
15
|
+
autoEdit: "Auto-allow file writes, ask only for shell commands",
|
|
16
|
+
readOnly: "Read only - block all file writes and shell commands"
|
|
17
17
|
};
|
|
18
18
|
var DEFAULT_SETTINGS = {
|
|
19
19
|
permission: "ask",
|
|
20
20
|
port: 3e3
|
|
21
21
|
};
|
|
22
22
|
function getConfigDir() {
|
|
23
|
-
if (process.env.FANLUC_CONFIG_DIR && process.env.FANLUC_CONFIG_DIR.trim())
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
if (process.env.FANLUC_CONFIG_DIR && process.env.FANLUC_CONFIG_DIR.trim()) {
|
|
24
|
+
return process.env.FANLUC_CONFIG_DIR.trim();
|
|
25
|
+
}
|
|
26
|
+
if (process.platform === "win32") {
|
|
26
27
|
const appData = process.env.APPDATA;
|
|
27
|
-
if (appData && appData.trim())
|
|
28
|
-
return path.join(appData, "fanluc");
|
|
29
|
-
}
|
|
28
|
+
if (appData && appData.trim()) return path.join(appData, "fanluc");
|
|
30
29
|
return path.join(os.homedir(), "AppData", "Roaming", "fanluc");
|
|
31
30
|
}
|
|
32
31
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
@@ -60,9 +59,8 @@ function loadSettings(configDir) {
|
|
|
60
59
|
} catch (e) {
|
|
61
60
|
console.warn(`[fanluc] Failed to parse settings.json:`, e);
|
|
62
61
|
}
|
|
63
|
-
const perm = parsed.permission;
|
|
64
62
|
const valid = ["ask", "autoEdit", "readOnly"];
|
|
65
|
-
const permission = valid.includes(
|
|
63
|
+
const permission = valid.includes(parsed.permission) ? parsed.permission : DEFAULT_SETTINGS.permission;
|
|
66
64
|
return { ...DEFAULT_SETTINGS, ...parsed, permission };
|
|
67
65
|
}
|
|
68
66
|
function saveSettings(settings, configDir) {
|
|
@@ -80,7 +78,7 @@ function ensureMcpJson(configDir) {
|
|
|
80
78
|
if (fs.existsSync(target)) return target;
|
|
81
79
|
try {
|
|
82
80
|
fs.writeFileSync(target, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
83
|
-
console.log(`[fanluc] Created empty mcp.json at ${target}
|
|
81
|
+
console.log(`[fanluc] Created empty mcp.json at ${target}`);
|
|
84
82
|
} catch {
|
|
85
83
|
}
|
|
86
84
|
return target;
|
|
@@ -107,18 +105,17 @@ function findFanlucMd(workspaceDir) {
|
|
|
107
105
|
}
|
|
108
106
|
return null;
|
|
109
107
|
}
|
|
108
|
+
var MAX_FANLUC_MD = 6e3;
|
|
110
109
|
function loadFanlucMd(workspaceDir) {
|
|
111
110
|
const found = findFanlucMd(workspaceDir);
|
|
112
111
|
if (!found) return null;
|
|
113
112
|
try {
|
|
114
113
|
const raw = fs.readFileSync(found, "utf-8").replace(/^\uFEFF/, "");
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.warn(`[fanluc] FANLUC.md too large (${content.length} chars), truncating to ${MAX_FANLUC_MD}`);
|
|
119
|
-
return { path: found, content: content.slice(0, MAX_FANLUC_MD) + "\n\n[... truncated ...]" };
|
|
114
|
+
if (raw.length > MAX_FANLUC_MD) {
|
|
115
|
+
console.warn(`[fanluc] FANLUC.md too large (${raw.length} chars), truncating to ${MAX_FANLUC_MD}`);
|
|
116
|
+
return { path: found, content: raw.slice(0, MAX_FANLUC_MD) + "\n\n[... truncated ...]" };
|
|
120
117
|
}
|
|
121
|
-
return { path: found, content };
|
|
118
|
+
return { path: found, content: raw };
|
|
122
119
|
} catch (e) {
|
|
123
120
|
console.warn(`[fanluc] Failed to read ${found}:`, e);
|
|
124
121
|
return null;
|
|
@@ -128,7 +125,8 @@ function loadFanlucMd(workspaceDir) {
|
|
|
128
125
|
// src/cli/index.ts
|
|
129
126
|
var PKG = (() => {
|
|
130
127
|
try {
|
|
131
|
-
const
|
|
128
|
+
const here = path2.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
|
|
129
|
+
const pkgPath = path2.join(here, "..", "..", "package.json");
|
|
132
130
|
for (const p of [pkgPath, path2.join(process.cwd(), "package.json"), path2.join(path2.dirname(process.argv[1] ?? ""), "..", "package.json")]) {
|
|
133
131
|
if (fs2.existsSync(p)) {
|
|
134
132
|
const j = JSON.parse(fs2.readFileSync(p, "utf-8"));
|
|
@@ -141,7 +139,7 @@ var PKG = (() => {
|
|
|
141
139
|
})();
|
|
142
140
|
function printHelp() {
|
|
143
141
|
console.log(`
|
|
144
|
-
fanluc
|
|
142
|
+
fanluc - terminal tool like Claude Code / opencode (web UI runs alongside)
|
|
145
143
|
|
|
146
144
|
Usage:
|
|
147
145
|
fanluc [options] [workspace]
|
|
@@ -149,24 +147,26 @@ Usage:
|
|
|
149
147
|
fanluc --version
|
|
150
148
|
|
|
151
149
|
Options:
|
|
152
|
-
-p, --port <n> Port to listen (default from settings or 3000)
|
|
150
|
+
-p, --port <n> Port to listen on (default from settings or 3000)
|
|
153
151
|
--host <host> Host to bind (default 127.0.0.1)
|
|
154
|
-
--no-open Don't auto-open browser
|
|
155
|
-
--tui Force TUI (default: auto
|
|
156
|
-
--no-tui, --web No TUI,
|
|
152
|
+
--no-open Don't auto-open the browser
|
|
153
|
+
--tui Force TUI (default: auto when attached to a TTY)
|
|
154
|
+
--no-tui, --web No TUI, server + browser only
|
|
157
155
|
--permission <mode> Permission mode: ask | autoEdit | readOnly
|
|
158
|
-
(ask:
|
|
156
|
+
(ask: confirm every time, autoEdit: auto-allow file
|
|
157
|
+
writes, readOnly: read only)
|
|
159
158
|
|
|
160
159
|
Config:
|
|
161
|
-
Windows: %APPDATA%\\fanluc\\ (
|
|
160
|
+
Windows: %APPDATA%\\fanluc\\ (e.g. C:\\Users\\${os2.userInfo().username}\\AppData\\Roaming\\fanluc)
|
|
162
161
|
Linux/mac: ~/.config/fanluc/
|
|
163
162
|
- settings.json { permission, port, ... }
|
|
164
|
-
- mcp.json { mcpServers: {...} }
|
|
163
|
+
- mcp.json { mcpServers: {...} }
|
|
165
164
|
|
|
166
165
|
Workspace:
|
|
167
|
-
|
|
166
|
+
The current directory is the workspace. A FANLUC.md file in the
|
|
167
|
+
workspace is auto-loaded into the system prompt.
|
|
168
168
|
|
|
169
|
-
Permissions (3
|
|
169
|
+
Permissions (3 modes):
|
|
170
170
|
ask = ${PERMISSION_DESCRIPTIONS.ask}
|
|
171
171
|
autoEdit = ${PERMISSION_DESCRIPTIONS.autoEdit}
|
|
172
172
|
readOnly = ${PERMISSION_DESCRIPTIONS.readOnly}
|
|
@@ -177,7 +177,7 @@ Examples:
|
|
|
177
177
|
fanluc D:\\my-project
|
|
178
178
|
fanluc --no-open
|
|
179
179
|
|
|
180
|
-
Web
|
|
180
|
+
Web UI: http://localhost:<port>
|
|
181
181
|
`);
|
|
182
182
|
}
|
|
183
183
|
function printVersion() {
|
|
@@ -191,8 +191,7 @@ function parseArgs(argv) {
|
|
|
191
191
|
else if (a === "--version" || a === "-v") out.version = true;
|
|
192
192
|
else if (a === "--no-open") out.noOpen = true;
|
|
193
193
|
else if (a === "--port" || a === "-p") {
|
|
194
|
-
const
|
|
195
|
-
const n = parseInt(v, 10);
|
|
194
|
+
const n = parseInt(argv[++i], 10);
|
|
196
195
|
if (!isNaN(n)) out.port = n;
|
|
197
196
|
} else if (a.startsWith("--port=")) {
|
|
198
197
|
const n = parseInt(a.split("=")[1], 10);
|
|
@@ -220,21 +219,18 @@ function parseArgs(argv) {
|
|
|
220
219
|
return out;
|
|
221
220
|
}
|
|
222
221
|
function openBrowser(url) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (platform === "win32") {
|
|
226
|
-
cmd = `start "" "${url}"`;
|
|
227
|
-
exec(cmd, (err) => {
|
|
222
|
+
if (process.platform === "win32") {
|
|
223
|
+
exec(`start "" "${url}"`, (err) => {
|
|
228
224
|
if (err) {
|
|
229
225
|
exec(`powershell -NoProfile -Command "Start-Process '${url}'"`, (e2) => {
|
|
230
|
-
if (e2) console.warn(`[fanluc] Failed to open browser: ${e2.message}.
|
|
226
|
+
if (e2) console.warn(`[fanluc] Failed to open browser: ${e2.message}. Open manually: ${url}`);
|
|
231
227
|
else console.log(`[fanluc] Opened ${url} via PowerShell`);
|
|
232
228
|
});
|
|
233
229
|
} else {
|
|
234
230
|
console.log(`[fanluc] Opened ${url}`);
|
|
235
231
|
}
|
|
236
232
|
});
|
|
237
|
-
} else if (platform === "darwin") {
|
|
233
|
+
} else if (process.platform === "darwin") {
|
|
238
234
|
exec(`open "${url}"`, (err) => {
|
|
239
235
|
if (err) console.warn(`[fanluc] Failed to open browser: ${err.message}. Open manually: ${url}`);
|
|
240
236
|
else console.log(`[fanluc] Opened ${url}`);
|
|
@@ -258,7 +254,7 @@ async function main() {
|
|
|
258
254
|
}
|
|
259
255
|
const configDir = getConfigDir();
|
|
260
256
|
ensureConfigDir(configDir);
|
|
261
|
-
|
|
257
|
+
const settings = loadSettings(configDir);
|
|
262
258
|
if (args.permission) {
|
|
263
259
|
settings.permission = args.permission;
|
|
264
260
|
saveSettings(settings, configDir);
|
|
@@ -304,7 +300,8 @@ async function main() {
|
|
|
304
300
|
}
|
|
305
301
|
workspace = resolved;
|
|
306
302
|
} catch (e) {
|
|
307
|
-
|
|
303
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
304
|
+
console.error(`[fanluc] Workspace not found: ${resolved} - ${msg}`);
|
|
308
305
|
process.exit(1);
|
|
309
306
|
}
|
|
310
307
|
} else {
|
|
@@ -314,20 +311,19 @@ async function main() {
|
|
|
314
311
|
}
|
|
315
312
|
}
|
|
316
313
|
const fanlucMd = loadFanlucMd(workspace);
|
|
317
|
-
const configDirDisplay = configDir;
|
|
318
314
|
const mcpPath = path2.join(configDir, "mcp.json");
|
|
319
315
|
const settingsPath = path2.join(configDir, "settings.json");
|
|
320
316
|
console.log(`[fanluc] Install dir: ${installDir}`);
|
|
321
|
-
console.log(`[fanluc] Config dir : ${
|
|
317
|
+
console.log(`[fanluc] Config dir : ${configDir}`);
|
|
322
318
|
console.log(`[fanluc] - settings: ${settingsPath} (permission=${settings.permission})`);
|
|
323
319
|
console.log(`[fanluc] - mcp : ${mcpPath}`);
|
|
324
320
|
console.log(`[fanluc] Workspace : ${workspace}`);
|
|
325
321
|
if (fanlucMd) {
|
|
326
322
|
console.log(`[fanluc] FANLUC.md : ${fanlucMd.path} (${fanlucMd.content.length} chars, injected into system prompt)`);
|
|
327
323
|
} else {
|
|
328
|
-
console.log(`[fanluc] FANLUC.md : (none)
|
|
324
|
+
console.log(`[fanluc] FANLUC.md : (none) - create ${path2.join(workspace, "FANLUC.md")} to auto-inject`);
|
|
329
325
|
}
|
|
330
|
-
console.log(`[fanluc] Permission: ${settings.permission}
|
|
326
|
+
console.log(`[fanluc] Permission: ${settings.permission} - ${PERMISSION_DESCRIPTIONS[settings.permission]}`);
|
|
331
327
|
const port = settings.port || 3e3;
|
|
332
328
|
const host = settings.host || "127.0.0.1";
|
|
333
329
|
const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
|
|
@@ -347,7 +343,7 @@ async function main() {
|
|
|
347
343
|
serverEntry = serverCjs;
|
|
348
344
|
} else if (fs2.existsSync(serverTs)) {
|
|
349
345
|
console.error(`[fanluc] dist/server.cjs not found at ${serverCjs}`);
|
|
350
|
-
console.error(`[fanluc]
|
|
346
|
+
console.error(`[fanluc] Run 'npm run build:all' in ${installDir} first.`);
|
|
351
347
|
process.exit(1);
|
|
352
348
|
}
|
|
353
349
|
if (!serverEntry) {
|
|
@@ -358,12 +354,11 @@ async function main() {
|
|
|
358
354
|
console.log(`[fanluc] (installDir=${installDir}, workspace=${workspace})`);
|
|
359
355
|
const shouldUseTui = !args.noTui && (args.tui || !!process.stdout.isTTY);
|
|
360
356
|
let serverStdio = "inherit";
|
|
361
|
-
let serverLogPath = "";
|
|
362
357
|
if (shouldUseTui) {
|
|
363
358
|
try {
|
|
364
359
|
const cfgDir = getConfigDir();
|
|
365
360
|
fs2.mkdirSync(cfgDir, { recursive: true });
|
|
366
|
-
serverLogPath = path2.join(cfgDir, "server.log");
|
|
361
|
+
const serverLogPath = path2.join(cfgDir, "server.log");
|
|
367
362
|
const fd = fs2.openSync(serverLogPath, "w");
|
|
368
363
|
serverStdio = ["ignore", fd, fd];
|
|
369
364
|
process.env.FANLUC_SERVER_LOG = serverLogPath;
|
|
@@ -387,12 +382,11 @@ async function main() {
|
|
|
387
382
|
openBrowser(url);
|
|
388
383
|
}, 1500);
|
|
389
384
|
} else if (shouldUseTui) {
|
|
390
|
-
console.log(`[fanluc] TUI enabled
|
|
385
|
+
console.log(`[fanluc] TUI enabled - browser not auto-opened (use --web or --no-tui to open it). Web UI: ${url}`);
|
|
391
386
|
} else {
|
|
392
387
|
console.log(`[fanluc] Auto-open disabled (--no-open). Open manually: ${url}`);
|
|
393
388
|
}
|
|
394
|
-
const
|
|
395
|
-
for (const sig of signals) {
|
|
389
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
396
390
|
process.on(sig, () => {
|
|
397
391
|
console.log(`
|
|
398
392
|
[fanluc] Received ${sig}, shutting down...`);
|
|
@@ -419,7 +413,7 @@ async function main() {
|
|
|
419
413
|
}
|
|
420
414
|
console.log(`[fanluc] Starting TUI... (workspace: ${workspace}, FANLUC.md: ${fanlucMd ? fanlucMd.path : "none"})`);
|
|
421
415
|
try {
|
|
422
|
-
const tuiPath = path2.join(installDir, "dist
|
|
416
|
+
const tuiPath = path2.join(installDir, "dist", "tui.js");
|
|
423
417
|
if (!fs2.existsSync(tuiPath)) {
|
|
424
418
|
console.error(`[fanluc] TUI not built at ${tuiPath}. Run 'npm run build:tui' or 'npm run build:all' first.`);
|
|
425
419
|
console.error(`[fanluc] Falling back to browser. Open ${url} manually.`);
|
|
@@ -429,12 +423,12 @@ async function main() {
|
|
|
429
423
|
const fileUrl = `file://${tuiPath.replace(/\\/g, "/").replace(/^([A-Z]):/, "/$1:")}`;
|
|
430
424
|
const normalizedUrl = fileUrl.startsWith("file:////") ? fileUrl.replace("file:////", "file:///") : fileUrl;
|
|
431
425
|
const tuiMod = await import(normalizedUrl);
|
|
432
|
-
const startTui = tuiMod.startTui || tuiMod.default
|
|
426
|
+
const startTui = tuiMod.startTui || (typeof tuiMod.default === "function" ? tuiMod.default : tuiMod.default?.startTui);
|
|
433
427
|
if (typeof startTui !== "function") throw new Error("startTui not found in dist/tui.js");
|
|
434
428
|
const tuiConfig = {
|
|
435
429
|
apiUrl: settings.apiUrl || process.env.OPENAI_API_URL || process.env.API_URL || "",
|
|
436
430
|
apiKey: settings.apiKey || process.env.OPENAI_API_KEY || process.env.API_KEY || "none",
|
|
437
|
-
model: settings.model ||
|
|
431
|
+
model: settings.model || "",
|
|
438
432
|
systemPrompt: settings.systemPrompt || "",
|
|
439
433
|
temperature: settings.temperature ?? 0.7,
|
|
440
434
|
maxTokens: settings.maxTokens ?? 8e3,
|
|
@@ -462,9 +456,10 @@ async function main() {
|
|
|
462
456
|
}
|
|
463
457
|
});
|
|
464
458
|
} catch (e) {
|
|
465
|
-
|
|
466
|
-
console.error(e
|
|
467
|
-
console.error(
|
|
459
|
+
const err = e;
|
|
460
|
+
console.error(`[fanluc] TUI failed to start: ${err?.message || e}`);
|
|
461
|
+
console.error(err?.stack);
|
|
462
|
+
console.error(`[fanluc] Web UI: ${url}`);
|
|
468
463
|
}
|
|
469
464
|
}
|
|
470
465
|
}
|
package/dist/index.html
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>
|
|
7
|
-
<meta name="description" content="
|
|
6
|
+
<title>FANLUC</title>
|
|
7
|
+
<meta name="description" content="Self-hosted AI chat with a classic black-and-white terminal style. Custom REST API endpoint." />
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Inconsolata:wght@200..900&family=Lora:ital,wght@0,400..700;1,400..700&family=Share+Tech+Mono&family=VT323&display=swap" rel="stylesheet">
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-C8gDJtDK.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BEKLwzQT.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|