saeeol 1.4.4 → 1.4.5

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 (2) hide show
  1. package/desktop.js +142 -0
  2. package/package.json +9 -4
package/desktop.js ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+
3
+ // saeeol desktop — launches saeeol web server + Electron window
4
+ const { existsSync, realpathSync } = require("fs")
5
+ const { join, dirname } = require("path")
6
+ const { spawn } = require("child_process")
7
+
8
+ function getBinaryName() {
9
+ const archMap = { x64: "x64", arm64: "arm64" }
10
+ const platformMap = { win32: "windows", darwin: "darwin", linux: "linux" }
11
+ const p = platformMap[process.platform] || process.platform
12
+ const a = archMap[process.arch] || process.arch
13
+ return `saeeol-${p}-${a}`
14
+ }
15
+
16
+ function findBinary() {
17
+ const binaryName = getBinaryName()
18
+ const binaryRel = process.platform === "win32" ? "bin/saeeol.exe" : "bin/saeeol"
19
+ const scriptDir = dirname(realpathSync(__filename))
20
+
21
+ // 1. node_modules of this package
22
+ const local = join(scriptDir, "node_modules", binaryName, binaryRel)
23
+ if (existsSync(local)) return local
24
+
25
+ // 2. Walk up
26
+ let current = scriptDir
27
+ for (let i = 0; i < 10; i++) {
28
+ const candidate = join(current, "node_modules", binaryName, binaryRel)
29
+ if (existsSync(candidate)) return candidate
30
+ const parent = dirname(current)
31
+ if (parent === current) break
32
+ current = parent
33
+ }
34
+
35
+ // 3. Download dir
36
+ const dl = join(scriptDir, "download", process.platform === "win32" ? `${binaryName}.exe` : "saeeol")
37
+ if (existsSync(dl)) return dl
38
+
39
+ return null
40
+ }
41
+
42
+ function findElectron() {
43
+ const scriptDir = dirname(realpathSync(__filename))
44
+ const electronPath = join(scriptDir, "node_modules", "electron", "dist", process.platform === "win32" ? "electron.exe" : "electron")
45
+ if (existsSync(electronPath)) return electronPath
46
+ return null
47
+ }
48
+
49
+ async function main() {
50
+ const binaryPath = findBinary()
51
+ if (!binaryPath) {
52
+ console.error(`saeeol binary not found (${getBinaryName()})`)
53
+ console.error(`Run: npm install saeeol`)
54
+ process.exit(1)
55
+ }
56
+
57
+ const electronPath = findElectron()
58
+
59
+ // If no electron, fall back to CLI mode
60
+ if (!electronPath) {
61
+ console.log("Electron not found. Install with: npm install -g saeeol")
62
+ console.log("Starting in terminal mode...\n")
63
+ const child = spawn(binaryPath, process.argv.slice(2), {
64
+ stdio: "inherit",
65
+ env: { ...process.env },
66
+ windowsHide: false,
67
+ })
68
+ child.on("exit", (code) => process.exit(code || 0))
69
+ return
70
+ }
71
+
72
+ // Find free port
73
+ const port = 30000 + Math.floor(Math.random() * 10000)
74
+
75
+ console.log(`Starting saeeol server on port ${port}...`)
76
+
77
+ // Start saeeol web in background
78
+ const server = spawn(binaryPath, ["web", "--port", String(port), "--hostname", "127.0.0.1"], {
79
+ stdio: "pipe",
80
+ env: { ...process.env },
81
+ windowsHide: true,
82
+ })
83
+
84
+ server.stdout.on("data", (data) => {
85
+ const msg = data.toString().trim()
86
+ if (msg) console.log(`[server] ${msg}`)
87
+ })
88
+ server.stderr.on("data", (data) => {
89
+ const msg = data.toString().trim()
90
+ if (msg) console.error(`[server] ${msg}`)
91
+ })
92
+
93
+ // Create a minimal Electron app that loads the saeeol web URL
94
+ const electronApp = join(__dirname, "desktop-app.js")
95
+ const desktopAppCode = `
96
+ const { app, BrowserWindow } = require("electron")
97
+ const url = "http://127.0.0.1:${port}"
98
+
99
+ function createWindow() {
100
+ const win = new BrowserWindow({
101
+ width: 1400,
102
+ height: 900,
103
+ minWidth: 800,
104
+ minHeight: 600,
105
+ title: "파불리스트 — FABULIST",
106
+ autoHideMenuBar: true,
107
+ webPreferences: { nodeIntegration: false, contextIsolation: true },
108
+ })
109
+ win.loadURL(url)
110
+ }
111
+
112
+ app.whenReady().then(createWindow)
113
+ app.on("window-all-closed", () => {
114
+ app.quit()
115
+ process.kill(${server.pid})
116
+ process.exit(0)
117
+ })
118
+ `
119
+ require("fs").writeFileSync(electronApp, desktopAppCode)
120
+
121
+ // Wait a bit for server to start
122
+ await new Promise((r) => setTimeout(r, 3000))
123
+
124
+ console.log("Opening FABULIST desktop...")
125
+
126
+ const electron = spawn(electronPath, [electronApp], {
127
+ stdio: "inherit",
128
+ env: { ...process.env },
129
+ windowsHide: false,
130
+ })
131
+
132
+ electron.on("exit", (code) => {
133
+ server.kill()
134
+ try { require("fs").unlinkSync(electronApp) } catch {}
135
+ process.exit(code || 0)
136
+ })
137
+ }
138
+
139
+ main().catch((err) => {
140
+ console.error(err.message)
141
+ process.exit(1)
142
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saeeol",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "AI agent engine for SAEEOL",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,10 +8,12 @@
8
8
  "url": "https://github.com/byfabulist/fabulist"
9
9
  },
10
10
  "bin": {
11
- "saeeol": "cli.js"
11
+ "saeeol": "cli.js",
12
+ "fabulist": "desktop.js"
12
13
  },
13
14
  "files": [
14
15
  "cli.js",
16
+ "desktop.js",
15
17
  "postinstall.js"
16
18
  ],
17
19
  "scripts": {
@@ -29,7 +31,8 @@
29
31
  "saeeol-linux-arm64-musl": "1.4.3",
30
32
  "saeeol-linux-x64-musl": "1.4.3",
31
33
  "saeeol-linux-x64-musl-baseline": "1.4.3",
32
- "saeeol-win32-arm64": "1.4.3"
34
+ "saeeol-win32-arm64": "1.4.3",
35
+ "electron": "^35.2.1"
33
36
  },
34
37
  "publishConfig": {
35
38
  "access": "public",
@@ -44,6 +47,8 @@
44
47
  "cli",
45
48
  "coding",
46
49
  "assistant",
47
- "saeeol"
50
+ "saeeol",
51
+ "fabulist",
52
+ "desktop"
48
53
  ]
49
54
  }