clitrigger 0.1.14 → 0.1.16

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 (79) hide show
  1. package/README.md +15 -4
  2. package/README_KR.md +15 -4
  3. package/bin/clitrigger.js +41 -4
  4. package/dist/client/assets/index-BldpDcSD.js +686 -0
  5. package/dist/client/assets/{index-BDEcscfu.css → index-CRSNebDI.css} +1 -1
  6. package/dist/client/index.html +2 -2
  7. package/dist/server/db/app-settings.d.ts +3 -0
  8. package/dist/server/db/app-settings.d.ts.map +1 -0
  9. package/dist/server/db/app-settings.js +16 -0
  10. package/dist/server/db/app-settings.js.map +1 -0
  11. package/dist/server/db/queries.d.ts +27 -3
  12. package/dist/server/db/queries.d.ts.map +1 -1
  13. package/dist/server/db/queries.js +25 -5
  14. package/dist/server/db/queries.js.map +1 -1
  15. package/dist/server/db/schema.d.ts.map +1 -1
  16. package/dist/server/db/schema.js +23 -0
  17. package/dist/server/db/schema.js.map +1 -1
  18. package/dist/server/index.d.ts.map +1 -1
  19. package/dist/server/index.js +4 -2
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/routes/discussions.d.ts.map +1 -1
  22. package/dist/server/routes/discussions.js +1 -1
  23. package/dist/server/routes/discussions.js.map +1 -1
  24. package/dist/server/routes/memory.d.ts.map +1 -1
  25. package/dist/server/routes/memory.js +333 -0
  26. package/dist/server/routes/memory.js.map +1 -1
  27. package/dist/server/routes/sessions.d.ts.map +1 -1
  28. package/dist/server/routes/sessions.js +102 -3
  29. package/dist/server/routes/sessions.js.map +1 -1
  30. package/dist/server/routes/todos.js +2 -2
  31. package/dist/server/routes/todos.js.map +1 -1
  32. package/dist/server/routes/tunnel.d.ts.map +1 -1
  33. package/dist/server/routes/tunnel.js +37 -2
  34. package/dist/server/routes/tunnel.js.map +1 -1
  35. package/dist/server/services/discussion-orchestrator.d.ts.map +1 -1
  36. package/dist/server/services/discussion-orchestrator.js +2 -1
  37. package/dist/server/services/discussion-orchestrator.js.map +1 -1
  38. package/dist/server/services/memory-ingest.d.ts +4 -0
  39. package/dist/server/services/memory-ingest.d.ts.map +1 -1
  40. package/dist/server/services/memory-ingest.js +184 -21
  41. package/dist/server/services/memory-ingest.js.map +1 -1
  42. package/dist/server/services/memory-inject-hook.d.ts +3 -1
  43. package/dist/server/services/memory-inject-hook.d.ts.map +1 -1
  44. package/dist/server/services/memory-inject-hook.js +23 -3
  45. package/dist/server/services/memory-inject-hook.js.map +1 -1
  46. package/dist/server/services/memory-injector.d.ts +1 -1
  47. package/dist/server/services/memory-injector.d.ts.map +1 -1
  48. package/dist/server/services/memory-injector.js +18 -2
  49. package/dist/server/services/memory-injector.js.map +1 -1
  50. package/dist/server/services/memory-retriever.d.ts +16 -0
  51. package/dist/server/services/memory-retriever.d.ts.map +1 -0
  52. package/dist/server/services/memory-retriever.js +170 -0
  53. package/dist/server/services/memory-retriever.js.map +1 -0
  54. package/dist/server/services/orchestrator.d.ts.map +1 -1
  55. package/dist/server/services/orchestrator.js +2 -1
  56. package/dist/server/services/orchestrator.js.map +1 -1
  57. package/dist/server/services/session-manager.d.ts +22 -0
  58. package/dist/server/services/session-manager.d.ts.map +1 -1
  59. package/dist/server/services/session-manager.js +115 -3
  60. package/dist/server/services/session-manager.js.map +1 -1
  61. package/dist/server/services/tunnel-manager.d.ts +3 -1
  62. package/dist/server/services/tunnel-manager.d.ts.map +1 -1
  63. package/dist/server/services/tunnel-manager.js +18 -8
  64. package/dist/server/services/tunnel-manager.js.map +1 -1
  65. package/dist/server/services/wiki-exporter.d.ts +32 -0
  66. package/dist/server/services/wiki-exporter.d.ts.map +1 -0
  67. package/dist/server/services/wiki-exporter.js +430 -0
  68. package/dist/server/services/wiki-exporter.js.map +1 -0
  69. package/dist/server/services/wiki-index.d.ts +10 -0
  70. package/dist/server/services/wiki-index.d.ts.map +1 -0
  71. package/dist/server/services/wiki-index.js +100 -0
  72. package/dist/server/services/wiki-index.js.map +1 -0
  73. package/dist/server/websocket/index.d.ts.map +1 -1
  74. package/dist/server/websocket/index.js +8 -7
  75. package/dist/server/websocket/index.js.map +1 -1
  76. package/electron/main.cjs +224 -0
  77. package/electron/preload.cjs +3 -0
  78. package/package.json +58 -2
  79. package/dist/client/assets/index-uvmPjh-j.js +0 -654
@@ -0,0 +1,224 @@
1
+ const { app, BrowserWindow, dialog, shell, Menu, nativeTheme, clipboard } = require('electron');
2
+ const path = require('node:path');
3
+ const fs = require('node:fs');
4
+ const net = require('node:net');
5
+ const crypto = require('node:crypto');
6
+ const { pathToFileURL } = require('node:url');
7
+
8
+ let mainWindow = null;
9
+ let serverPort = null;
10
+ let serverPassword = null;
11
+ let cleanupStarted = false;
12
+
13
+ const userDataDir = app.getPath('userData');
14
+ const configFile = path.join(userDataDir, 'config.json');
15
+ const dbPath = path.join(userDataDir, 'clitrigger.db');
16
+
17
+ function readOrInitConfig() {
18
+ fs.mkdirSync(userDataDir, { recursive: true });
19
+ let config = {};
20
+ if (fs.existsSync(configFile)) {
21
+ try { config = JSON.parse(fs.readFileSync(configFile, 'utf-8')); } catch {}
22
+ }
23
+ let mutated = false;
24
+ if (!config.password) {
25
+ config.password = crypto.randomBytes(16).toString('hex');
26
+ mutated = true;
27
+ }
28
+ if (typeof config.port !== 'number') {
29
+ config.port = 3737;
30
+ mutated = true;
31
+ }
32
+ if (typeof config.tunnel !== 'boolean') {
33
+ config.tunnel = false;
34
+ mutated = true;
35
+ }
36
+ if (mutated) fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
37
+ return config;
38
+ }
39
+
40
+ function isPortFree(port) {
41
+ return new Promise((resolve) => {
42
+ const srv = net.createServer();
43
+ srv.once('error', () => resolve(false));
44
+ srv.once('listening', () => srv.close(() => resolve(true)));
45
+ srv.listen(port, '127.0.0.1');
46
+ });
47
+ }
48
+
49
+ async function findFreePort(start) {
50
+ for (let p = start; p < start + 50; p++) {
51
+ if (await isPortFree(p)) return p;
52
+ }
53
+ throw new Error('No free port available');
54
+ }
55
+
56
+ async function waitForServer(port, timeoutMs = 30000) {
57
+ const deadline = Date.now() + timeoutMs;
58
+ while (Date.now() < deadline) {
59
+ try {
60
+ const res = await fetch(`http://127.0.0.1:${port}/api/health`);
61
+ if (res.ok) return;
62
+ } catch {}
63
+ await new Promise((r) => setTimeout(r, 200));
64
+ }
65
+ throw new Error(`Server did not respond on port ${port} within ${timeoutMs}ms`);
66
+ }
67
+
68
+ function resolveServerEntry() {
69
+ const candidates = [
70
+ path.join(__dirname, '..', 'dist', 'server', 'index.js'),
71
+ path.join(process.resourcesPath || '', 'app.asar', 'dist', 'server', 'index.js'),
72
+ ];
73
+ return candidates.find((p) => p && fs.existsSync(p));
74
+ }
75
+
76
+ async function bootServer() {
77
+ const config = readOrInitConfig();
78
+ serverPassword = config.password;
79
+ serverPort = await findFreePort(config.port);
80
+
81
+ process.env.PORT = String(serverPort);
82
+ process.env.AUTH_PASSWORD = config.password;
83
+ process.env.DB_PATH = dbPath;
84
+ if (config.tunnel) process.env.TUNNEL_ENABLED = 'true';
85
+ if (config.tunnelName) process.env.TUNNEL_NAME = config.tunnelName;
86
+ if (config.tunnelHostname) process.env.TUNNEL_HOSTNAME = config.tunnelHostname;
87
+
88
+ const serverEntry = resolveServerEntry();
89
+ if (!serverEntry) {
90
+ throw new Error(
91
+ 'Server build not found. Run "npm run build" before launching Electron.'
92
+ );
93
+ }
94
+ await import(pathToFileURL(serverEntry).href);
95
+ await waitForServer(serverPort);
96
+ return { port: serverPort, password: config.password };
97
+ }
98
+
99
+ function createWindow(port) {
100
+ mainWindow = new BrowserWindow({
101
+ width: 1400,
102
+ height: 900,
103
+ minWidth: 800,
104
+ minHeight: 600,
105
+ backgroundColor: nativeTheme.shouldUseDarkColors ? '#0f0f0f' : '#ffffff',
106
+ webPreferences: {
107
+ preload: path.join(__dirname, 'preload.cjs'),
108
+ contextIsolation: true,
109
+ nodeIntegration: false,
110
+ sandbox: false,
111
+ },
112
+ });
113
+
114
+ const localOrigins = [
115
+ `http://127.0.0.1:${port}`,
116
+ `http://localhost:${port}`,
117
+ ];
118
+ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
119
+ const isLocal = localOrigins.some((o) => url.startsWith(o));
120
+ if (!isLocal) {
121
+ shell.openExternal(url);
122
+ return { action: 'deny' };
123
+ }
124
+ return { action: 'allow' };
125
+ });
126
+
127
+ mainWindow.loadURL(`http://127.0.0.1:${port}`);
128
+
129
+ if (!app.isPackaged) {
130
+ mainWindow.webContents.openDevTools({ mode: 'detach' });
131
+ }
132
+
133
+ mainWindow.on('closed', () => { mainWindow = null; });
134
+ }
135
+
136
+ function showPasswordDialog() {
137
+ const result = dialog.showMessageBoxSync(mainWindow, {
138
+ type: 'info',
139
+ title: 'CLITrigger',
140
+ message: 'Login password',
141
+ detail: serverPassword,
142
+ buttons: ['Copy to clipboard', 'Close'],
143
+ defaultId: 0,
144
+ cancelId: 1,
145
+ });
146
+ if (result === 0 && serverPassword) {
147
+ clipboard.writeText(serverPassword);
148
+ }
149
+ }
150
+
151
+ function buildMenu() {
152
+ const isMac = process.platform === 'darwin';
153
+ const template = [
154
+ ...(isMac ? [{ role: 'appMenu' }] : []),
155
+ {
156
+ label: 'File',
157
+ submenu: [
158
+ isMac ? { role: 'close' } : { role: 'quit' },
159
+ ],
160
+ },
161
+ { role: 'editMenu' },
162
+ { role: 'viewMenu' },
163
+ { role: 'windowMenu' },
164
+ {
165
+ label: 'Help',
166
+ submenu: [
167
+ { label: 'Show login password', click: showPasswordDialog },
168
+ { label: 'Open config folder', click: () => shell.openPath(userDataDir) },
169
+ { type: 'separator' },
170
+ {
171
+ label: 'Open in browser',
172
+ click: () => {
173
+ if (serverPort) shell.openExternal(`http://127.0.0.1:${serverPort}`);
174
+ },
175
+ },
176
+ ],
177
+ },
178
+ ];
179
+ Menu.setApplicationMenu(Menu.buildFromTemplate(template));
180
+ }
181
+
182
+ app.on('window-all-closed', () => {
183
+ if (process.platform !== 'darwin') app.quit();
184
+ });
185
+
186
+ app.on('activate', () => {
187
+ if (BrowserWindow.getAllWindows().length === 0 && serverPort) {
188
+ createWindow(serverPort);
189
+ }
190
+ });
191
+
192
+ app.on('before-quit', (event) => {
193
+ if (cleanupStarted) return;
194
+ cleanupStarted = true;
195
+ event.preventDefault();
196
+ process.emit('SIGTERM');
197
+ setTimeout(() => app.exit(0), 5000);
198
+ });
199
+
200
+ const gotLock = app.requestSingleInstanceLock();
201
+ if (!gotLock) {
202
+ app.quit();
203
+ } else {
204
+ app.on('second-instance', () => {
205
+ if (mainWindow) {
206
+ if (mainWindow.isMinimized()) mainWindow.restore();
207
+ mainWindow.focus();
208
+ }
209
+ });
210
+
211
+ app.whenReady().then(async () => {
212
+ try {
213
+ const { port } = await bootServer();
214
+ buildMenu();
215
+ createWindow(port);
216
+ } catch (err) {
217
+ dialog.showErrorBox(
218
+ 'CLITrigger failed to start',
219
+ String((err && err.stack) || err)
220
+ );
221
+ app.exit(1);
222
+ }
223
+ });
224
+ }
@@ -0,0 +1,3 @@
1
+ // Intentionally empty: the renderer talks to the local Express server over HTTP/WebSocket.
2
+ // Kept as a placeholder so contextIsolation has a preload to attach to, and
3
+ // future native bridges (file picker, clipboard, OS auth) have a home.
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "clitrigger",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
+ "main": "electron/main.cjs",
5
6
  "bin": {
6
7
  "clitrigger": "bin/clitrigger.js"
7
8
  },
8
9
  "files": [
9
10
  "dist/",
10
11
  "bin/",
12
+ "electron/",
11
13
  ".env.example",
12
14
  "README_KR.md"
13
15
  ],
@@ -35,7 +37,13 @@
35
37
  "build:plugin": "npm run build && npx esbuild dist/server/index.js --bundle --platform=node --format=esm --outfile=plugin-build/server/server.js --external:better-sqlite3 --external:node-pty",
36
38
  "docs:erd": "tsx scripts/generate-erd.ts",
37
39
  "docs:erd:check": "tsx scripts/generate-erd.ts --check",
38
- "postuninstall": "node bin/postuninstall.js"
40
+ "postuninstall": "node bin/postuninstall.js",
41
+ "electron:rebuild": "electron-rebuild -o better-sqlite3",
42
+ "electron:dev": "npm run build && electron .",
43
+ "electron:build": "npm run build && electron-builder",
44
+ "electron:build:win": "npm run build && electron-builder --win",
45
+ "electron:build:mac": "npm run build && electron-builder --mac",
46
+ "electron:build:linux": "npm run build && electron-builder --linux"
39
47
  },
40
48
  "dependencies": {
41
49
  "@iarna/toml": "^2.2.5",
@@ -56,6 +64,7 @@
56
64
  "ws": "^8.18.0"
57
65
  },
58
66
  "devDependencies": {
67
+ "@electron/rebuild": "^3.7.0",
59
68
  "@types/better-sqlite3": "^7.6.12",
60
69
  "@types/cors": "^2.8.17",
61
70
  "@types/express": "^5.0.0",
@@ -67,9 +76,56 @@
67
76
  "@types/ws": "^8.5.13",
68
77
  "@vitest/coverage-v8": "^4.1.1",
69
78
  "concurrently": "^9.1.0",
79
+ "electron": "^33.2.0",
80
+ "electron-builder": "^25.1.8",
70
81
  "esbuild": "^0.27.0",
71
82
  "tsx": "^4.19.0",
72
83
  "typescript": "^5.7.0",
73
84
  "vitest": "^4.1.1"
85
+ },
86
+ "build": {
87
+ "appId": "com.clitrigger.app",
88
+ "productName": "CLITrigger",
89
+ "directories": {
90
+ "output": "release"
91
+ },
92
+ "files": [
93
+ "dist/**/*",
94
+ "electron/**/*",
95
+ "bin/**/*",
96
+ "package.json",
97
+ "!**/*.map",
98
+ "!**/*.ts",
99
+ "!**/__tests__/**",
100
+ "!**/*.test.*"
101
+ ],
102
+ "asar": true,
103
+ "asarUnpack": [
104
+ "node_modules/better-sqlite3/**",
105
+ "node_modules/node-pty/**",
106
+ "node_modules/cloudflared/**"
107
+ ],
108
+ "mac": {
109
+ "category": "public.app-category.developer-tools",
110
+ "target": [
111
+ { "target": "dmg", "arch": ["x64", "arm64"] },
112
+ { "target": "zip", "arch": ["x64", "arm64"] }
113
+ ]
114
+ },
115
+ "win": {
116
+ "target": [
117
+ { "target": "nsis", "arch": ["x64"] },
118
+ { "target": "portable", "arch": ["x64"] }
119
+ ]
120
+ },
121
+ "linux": {
122
+ "category": "Development",
123
+ "target": ["AppImage"]
124
+ },
125
+ "nsis": {
126
+ "oneClick": false,
127
+ "allowToChangeInstallationDirectory": true,
128
+ "perMachine": false
129
+ }
74
130
  }
75
131
  }