omnikey-cli 1.0.5 → 1.0.7
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 +4 -1
- package/backend-dist/config.js +11 -1
- package/backend-dist/db.js +9 -5
- package/dist/daemon.js +55 -2
- package/dist/onboard.js +3 -9
- package/dist/removeConfig.js +42 -9
- package/package.json +1 -1
- package/src/daemon.ts +56 -2
- package/src/onboard.ts +3 -9
- package/src/removeConfig.ts +41 -9
package/README.md
CHANGED
|
@@ -27,11 +27,14 @@ omnikey onboard
|
|
|
27
27
|
# Or onboard non-interactively
|
|
28
28
|
omnikey onboard --open-ai-key YOUR_KEY
|
|
29
29
|
|
|
30
|
-
# Running the daemon will
|
|
30
|
+
# Running the daemon will set up a launchd agent and keep the backend server running across system restarts
|
|
31
31
|
omnikey daemon --port 7071
|
|
32
32
|
|
|
33
33
|
# Kill the daemon
|
|
34
34
|
omnikey kill-daemon --port 7071
|
|
35
|
+
|
|
36
|
+
# Remove the config directory and SQLite database (and launchd agent)
|
|
37
|
+
omnikey remove-config
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
## Development
|
package/backend-dist/config.js
CHANGED
|
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.config = void 0;
|
|
7
7
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
8
10
|
dotenv_1.default.config();
|
|
9
11
|
function getEnv(name, required) {
|
|
10
12
|
const value = process.env[name];
|
|
@@ -33,6 +35,14 @@ function getNumberEnv(name, defaultValue) {
|
|
|
33
35
|
}
|
|
34
36
|
return parsed;
|
|
35
37
|
}
|
|
38
|
+
function getSqlitePath() {
|
|
39
|
+
const envPath = getEnv('SQLITE_PATH', false);
|
|
40
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || os_1.default.homedir();
|
|
41
|
+
const defaultPath = path_1.default.join(homeDir, '.omnikey', 'omnikey-selfhosted.sqlite');
|
|
42
|
+
if (!envPath)
|
|
43
|
+
return defaultPath;
|
|
44
|
+
return path_1.default.isAbsolute(envPath) ? envPath : path_1.default.join(homeDir, '.omnikey', envPath);
|
|
45
|
+
}
|
|
36
46
|
exports.config = {
|
|
37
47
|
// Server
|
|
38
48
|
logLevel: getEnv('LOG_LEVEL', false) || 'info',
|
|
@@ -42,7 +52,7 @@ exports.config = {
|
|
|
42
52
|
// Database
|
|
43
53
|
databaseUrl: getEnv('DATABASE_URL', getBooleanEnv('IS_SELF_HOSTED', false) ? false : true),
|
|
44
54
|
dbLogging: getBooleanEnv('DB_LOGGING', false),
|
|
45
|
-
sqlitePath:
|
|
55
|
+
sqlitePath: getSqlitePath(),
|
|
46
56
|
// Crypto
|
|
47
57
|
appEncryptionKey: getEnv('APP_ENCRYPTION_KEY', false),
|
|
48
58
|
// JWT / auth
|
package/backend-dist/db.js
CHANGED
|
@@ -24,11 +24,15 @@ else if (config_1.config.databaseUrl) {
|
|
|
24
24
|
async function initDatabase(logger) {
|
|
25
25
|
try {
|
|
26
26
|
await sequelize.authenticate();
|
|
27
|
-
// Use `alter: true`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
// Use `alter: true` only for Postgres, not for SQLite
|
|
28
|
+
if (sequelize.getDialect() === 'sqlite') {
|
|
29
|
+
await sequelize.sync();
|
|
30
|
+
logger.info('Database connection established and models synchronized (SQLite, no alter).');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await sequelize.sync({ alter: true });
|
|
34
|
+
logger.info('Database connection established and models synchronized (alter: true).');
|
|
35
|
+
}
|
|
32
36
|
}
|
|
33
37
|
catch (err) {
|
|
34
38
|
logger.error('Unable to connect to the database:', err);
|
package/dist/daemon.js
CHANGED
|
@@ -7,8 +7,11 @@ exports.startDaemon = startDaemon;
|
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const child_process_2 = require("child_process");
|
|
10
12
|
/**
|
|
11
13
|
* Start the Omnikey API backend as a daemon on the specified port.
|
|
14
|
+
* Also creates and registers a launchd agent for persistence on macOS.
|
|
12
15
|
* @param port The port to run the backend on
|
|
13
16
|
*/
|
|
14
17
|
function startDaemon(port = 7071) {
|
|
@@ -16,7 +19,8 @@ function startDaemon(port = 7071) {
|
|
|
16
19
|
// Path to the backend entry point (now from backend-dist)
|
|
17
20
|
const backendPath = path_1.default.resolve(__dirname, '../backend-dist/index.js');
|
|
18
21
|
// Read and update environment variables from ~/.omnikey/config.json
|
|
19
|
-
const
|
|
22
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || os_1.default.homedir();
|
|
23
|
+
const configDir = path_1.default.join(homeDir, '.omnikey');
|
|
20
24
|
const configPath = path_1.default.join(configDir, 'config.json');
|
|
21
25
|
let configVars = {};
|
|
22
26
|
if (fs_1.default.existsSync(configPath)) {
|
|
@@ -37,7 +41,56 @@ function startDaemon(port = 7071) {
|
|
|
37
41
|
catch (e) {
|
|
38
42
|
console.error('Failed to write updated config.json:', e);
|
|
39
43
|
}
|
|
40
|
-
//
|
|
44
|
+
// Create launchd agent for persistence
|
|
45
|
+
const plistName = 'com.omnikey.daemon.plist';
|
|
46
|
+
const plistPath = path_1.default.join(homeDir, 'Library', 'LaunchAgents', plistName);
|
|
47
|
+
const nodePath = process.execPath;
|
|
48
|
+
const envVars = Object.entries({ ...configVars, OMNIKEY_PORT: String(port) })
|
|
49
|
+
.map(([k, v]) => `<key>${k}</key><string>${v}</string>`)
|
|
50
|
+
.join('\n');
|
|
51
|
+
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
52
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
53
|
+
<plist version="1.0">
|
|
54
|
+
<dict>
|
|
55
|
+
<key>Label</key>
|
|
56
|
+
<string>com.omnikey.daemon</string>
|
|
57
|
+
<key>ProgramArguments</key>
|
|
58
|
+
<array>
|
|
59
|
+
<string>${nodePath}</string>
|
|
60
|
+
<string>${backendPath}</string>
|
|
61
|
+
</array>
|
|
62
|
+
<key>EnvironmentVariables</key>
|
|
63
|
+
<dict>
|
|
64
|
+
${envVars}
|
|
65
|
+
</dict>
|
|
66
|
+
<key>RunAtLoad</key>
|
|
67
|
+
<true/>
|
|
68
|
+
<key>KeepAlive</key>
|
|
69
|
+
<true/>
|
|
70
|
+
<key>StandardOutPath</key>
|
|
71
|
+
<string>${path_1.default.join(configDir, 'daemon.log')}</string>
|
|
72
|
+
<key>StandardErrorPath</key>
|
|
73
|
+
<string>${path_1.default.join(configDir, 'daemon-error.log')}</string>
|
|
74
|
+
<key>WorkingDirectory</key>
|
|
75
|
+
<string>${configDir}</string>
|
|
76
|
+
</dict>
|
|
77
|
+
</plist>
|
|
78
|
+
`;
|
|
79
|
+
// Write plist file
|
|
80
|
+
try {
|
|
81
|
+
const launchAgentsDir = path_1.default.join(homeDir, 'Library', 'LaunchAgents');
|
|
82
|
+
fs_1.default.mkdirSync(launchAgentsDir, { recursive: true });
|
|
83
|
+
fs_1.default.writeFileSync(plistPath, plistContent, 'utf-8');
|
|
84
|
+
// Load the launch agent
|
|
85
|
+
(0, child_process_2.execSync)(`launchctl unload "${plistPath}" || true`); // Unload if already loaded
|
|
86
|
+
(0, child_process_2.execSync)(`launchctl load "${plistPath}"`);
|
|
87
|
+
console.log(`Launch agent created and loaded: ${plistPath}`);
|
|
88
|
+
console.log('Omnikey daemon will auto-restart and persist across reboots.');
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.error('Failed to create or load launch agent:', e);
|
|
92
|
+
}
|
|
93
|
+
// Also start the backend immediately for current session
|
|
41
94
|
const child = (0, child_process_1.spawn)('node', [backendPath], {
|
|
42
95
|
env: { ...process.env, ...configVars, OMNIKEY_PORT: String(port) },
|
|
43
96
|
detached: true,
|
package/dist/onboard.js
CHANGED
|
@@ -13,7 +13,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
13
|
*/
|
|
14
14
|
async function onboard(openAiKey) {
|
|
15
15
|
let apiKey = openAiKey;
|
|
16
|
-
|
|
16
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '.';
|
|
17
|
+
const configDir = path_1.default.join(homeDir, '.omnikey');
|
|
18
|
+
const sqlitePath = path_1.default.join(configDir, 'omnikey-selfhosted.sqlite');
|
|
17
19
|
if (!apiKey) {
|
|
18
20
|
const answers = await inquirer_1.default.prompt([
|
|
19
21
|
{
|
|
@@ -22,18 +24,10 @@ async function onboard(openAiKey) {
|
|
|
22
24
|
message: 'Enter your OPENAI_API_KEY:',
|
|
23
25
|
validate: (input) => input.trim() !== '' || 'API key cannot be empty',
|
|
24
26
|
},
|
|
25
|
-
{
|
|
26
|
-
type: 'input',
|
|
27
|
-
name: 'sqlitePath',
|
|
28
|
-
message: 'SQLite DB file path:',
|
|
29
|
-
default: 'omnikey-selfhosted.sqlite',
|
|
30
|
-
},
|
|
31
27
|
]);
|
|
32
28
|
apiKey = answers.apiKey;
|
|
33
|
-
sqlitePath = answers.sqlitePath;
|
|
34
29
|
}
|
|
35
30
|
// Save all environment variables to ~/.omnikey/config.json
|
|
36
|
-
const configDir = path_1.default.join(process.env.HOME || process.env.USERPROFILE || '.', '.omnikey');
|
|
37
31
|
const configPath = path_1.default.join(configDir, 'config.json');
|
|
38
32
|
fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
39
33
|
const configVars = {
|
package/dist/removeConfig.js
CHANGED
|
@@ -6,25 +6,45 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.removeConfigAndDb = removeConfigAndDb;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
9
11
|
/**
|
|
10
|
-
* Removes the ~/.omnikey config directory and the
|
|
12
|
+
* Removes the ~/.omnikey config directory and the SQLite database file specified in config.json.
|
|
11
13
|
*/
|
|
12
14
|
function removeConfigAndDb() {
|
|
13
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE ||
|
|
15
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || os_1.default.homedir();
|
|
14
16
|
const configDir = path_1.default.join(homeDir, '.omnikey');
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const configPath = path_1.default.join(configDir, 'config.json');
|
|
18
|
+
let sqlitePath = path_1.default.join(homeDir, 'omnikey-selfhosted.sqlite');
|
|
19
|
+
// Try to read SQLITE_PATH from config.json
|
|
20
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
18
21
|
try {
|
|
19
|
-
fs_1.default.
|
|
20
|
-
|
|
22
|
+
const configData = JSON.parse(fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
23
|
+
if (configData.SQLITE_PATH) {
|
|
24
|
+
sqlitePath = path_1.default.isAbsolute(configData.SQLITE_PATH)
|
|
25
|
+
? configData.SQLITE_PATH
|
|
26
|
+
: path_1.default.join(homeDir, configData.SQLITE_PATH);
|
|
27
|
+
}
|
|
21
28
|
}
|
|
22
29
|
catch (e) {
|
|
23
|
-
console.error(`Failed to
|
|
30
|
+
console.error(`Failed to read config.json: ${e}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Remove launchd agent if exists (macOS)
|
|
34
|
+
const plistName = 'com.omnikey.daemon.plist';
|
|
35
|
+
const plistPath = path_1.default.join(homeDir, 'Library', 'LaunchAgents', plistName);
|
|
36
|
+
if (fs_1.default.existsSync(plistPath)) {
|
|
37
|
+
try {
|
|
38
|
+
(0, child_process_1.execSync)(`launchctl unload "${plistPath}"`);
|
|
39
|
+
fs_1.default.rmSync(plistPath);
|
|
40
|
+
console.log(`Removed launchd agent: ${plistPath}`);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
console.error(`Failed to remove launchd agent: ${e}`);
|
|
24
44
|
}
|
|
25
45
|
}
|
|
26
46
|
else {
|
|
27
|
-
console.log(`
|
|
47
|
+
console.log(`Launchd agent does not exist: ${plistPath}`);
|
|
28
48
|
}
|
|
29
49
|
// Remove SQLite database
|
|
30
50
|
if (fs_1.default.existsSync(sqlitePath)) {
|
|
@@ -39,4 +59,17 @@ function removeConfigAndDb() {
|
|
|
39
59
|
else {
|
|
40
60
|
console.log(`SQLite database does not exist: ${sqlitePath}`);
|
|
41
61
|
}
|
|
62
|
+
// Remove .omnikey directory
|
|
63
|
+
if (fs_1.default.existsSync(configDir)) {
|
|
64
|
+
try {
|
|
65
|
+
fs_1.default.rmSync(configDir, { recursive: true, force: true });
|
|
66
|
+
console.log(`Removed config directory: ${configDir}`);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.error(`Failed to remove config directory: ${e}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log(`Config directory does not exist: ${configDir}`);
|
|
74
|
+
}
|
|
42
75
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"registry": "https://registry.npmjs.org/"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.7",
|
|
8
8
|
"description": "CLI for onboarding users to Omnikey AI and configuring OPENAI_API_KEY. Use Yarn for install/build.",
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=14.0.0",
|
package/src/daemon.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Start the Omnikey API backend as a daemon on the specified port.
|
|
9
|
+
* Also creates and registers a launchd agent for persistence on macOS.
|
|
7
10
|
* @param port The port to run the backend on
|
|
8
11
|
*/
|
|
9
12
|
export function startDaemon(port: number = 7071) {
|
|
@@ -13,7 +16,8 @@ export function startDaemon(port: number = 7071) {
|
|
|
13
16
|
const backendPath = path.resolve(__dirname, '../backend-dist/index.js');
|
|
14
17
|
|
|
15
18
|
// Read and update environment variables from ~/.omnikey/config.json
|
|
16
|
-
const
|
|
19
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
20
|
+
const configDir = path.join(homeDir, '.omnikey');
|
|
17
21
|
const configPath = path.join(configDir, 'config.json');
|
|
18
22
|
let configVars: Record<string, any> = {};
|
|
19
23
|
if (fs.existsSync(configPath)) {
|
|
@@ -32,7 +36,57 @@ export function startDaemon(port: number = 7071) {
|
|
|
32
36
|
} catch (e) {
|
|
33
37
|
console.error('Failed to write updated config.json:', e);
|
|
34
38
|
}
|
|
35
|
-
|
|
39
|
+
|
|
40
|
+
// Create launchd agent for persistence
|
|
41
|
+
const plistName = 'com.omnikey.daemon.plist';
|
|
42
|
+
const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', plistName);
|
|
43
|
+
const nodePath = process.execPath;
|
|
44
|
+
const envVars = Object.entries({ ...configVars, OMNIKEY_PORT: String(port) })
|
|
45
|
+
.map(([k, v]) => `<key>${k}</key><string>${v}</string>`)
|
|
46
|
+
.join('\n');
|
|
47
|
+
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
48
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
49
|
+
<plist version="1.0">
|
|
50
|
+
<dict>
|
|
51
|
+
<key>Label</key>
|
|
52
|
+
<string>com.omnikey.daemon</string>
|
|
53
|
+
<key>ProgramArguments</key>
|
|
54
|
+
<array>
|
|
55
|
+
<string>${nodePath}</string>
|
|
56
|
+
<string>${backendPath}</string>
|
|
57
|
+
</array>
|
|
58
|
+
<key>EnvironmentVariables</key>
|
|
59
|
+
<dict>
|
|
60
|
+
${envVars}
|
|
61
|
+
</dict>
|
|
62
|
+
<key>RunAtLoad</key>
|
|
63
|
+
<true/>
|
|
64
|
+
<key>KeepAlive</key>
|
|
65
|
+
<true/>
|
|
66
|
+
<key>StandardOutPath</key>
|
|
67
|
+
<string>${path.join(configDir, 'daemon.log')}</string>
|
|
68
|
+
<key>StandardErrorPath</key>
|
|
69
|
+
<string>${path.join(configDir, 'daemon-error.log')}</string>
|
|
70
|
+
<key>WorkingDirectory</key>
|
|
71
|
+
<string>${configDir}</string>
|
|
72
|
+
</dict>
|
|
73
|
+
</plist>
|
|
74
|
+
`;
|
|
75
|
+
// Write plist file
|
|
76
|
+
try {
|
|
77
|
+
const launchAgentsDir = path.join(homeDir, 'Library', 'LaunchAgents');
|
|
78
|
+
fs.mkdirSync(launchAgentsDir, { recursive: true });
|
|
79
|
+
fs.writeFileSync(plistPath, plistContent, 'utf-8');
|
|
80
|
+
// Load the launch agent
|
|
81
|
+
execSync(`launchctl unload "${plistPath}" || true`); // Unload if already loaded
|
|
82
|
+
execSync(`launchctl load "${plistPath}"`);
|
|
83
|
+
console.log(`Launch agent created and loaded: ${plistPath}`);
|
|
84
|
+
console.log('Omnikey daemon will auto-restart and persist across reboots.');
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.error('Failed to create or load launch agent:', e);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Also start the backend immediately for current session
|
|
36
90
|
const child = spawn('node', [backendPath], {
|
|
37
91
|
env: { ...process.env, ...configVars, OMNIKEY_PORT: String(port) },
|
|
38
92
|
detached: true,
|
package/src/onboard.ts
CHANGED
|
@@ -8,7 +8,9 @@ import path from 'path';
|
|
|
8
8
|
*/
|
|
9
9
|
export async function onboard(openAiKey?: string) {
|
|
10
10
|
let apiKey = openAiKey;
|
|
11
|
-
|
|
11
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '.';
|
|
12
|
+
const configDir = path.join(homeDir, '.omnikey');
|
|
13
|
+
const sqlitePath = path.join(configDir, 'omnikey-selfhosted.sqlite');
|
|
12
14
|
|
|
13
15
|
if (!apiKey) {
|
|
14
16
|
const answers = await inquirer.prompt([
|
|
@@ -18,19 +20,11 @@ export async function onboard(openAiKey?: string) {
|
|
|
18
20
|
message: 'Enter your OPENAI_API_KEY:',
|
|
19
21
|
validate: (input: string) => input.trim() !== '' || 'API key cannot be empty',
|
|
20
22
|
},
|
|
21
|
-
{
|
|
22
|
-
type: 'input',
|
|
23
|
-
name: 'sqlitePath',
|
|
24
|
-
message: 'SQLite DB file path:',
|
|
25
|
-
default: 'omnikey-selfhosted.sqlite',
|
|
26
|
-
},
|
|
27
23
|
]);
|
|
28
24
|
apiKey = answers.apiKey;
|
|
29
|
-
sqlitePath = answers.sqlitePath;
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
// Save all environment variables to ~/.omnikey/config.json
|
|
33
|
-
const configDir = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.omnikey');
|
|
34
28
|
const configPath = path.join(configDir, 'config.json');
|
|
35
29
|
fs.mkdirSync(configDir, { recursive: true });
|
|
36
30
|
const configVars = {
|
package/src/removeConfig.ts
CHANGED
|
@@ -1,24 +1,44 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
* Removes the ~/.omnikey config directory and the
|
|
7
|
+
* Removes the ~/.omnikey config directory and the SQLite database file specified in config.json.
|
|
6
8
|
*/
|
|
7
9
|
export function removeConfigAndDb() {
|
|
8
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE ||
|
|
10
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
9
11
|
const configDir = path.join(homeDir, '.omnikey');
|
|
10
|
-
const
|
|
12
|
+
const configPath = path.join(configDir, 'config.json');
|
|
13
|
+
let sqlitePath = path.join(homeDir, 'omnikey-selfhosted.sqlite');
|
|
11
14
|
|
|
12
|
-
//
|
|
13
|
-
if (fs.existsSync(
|
|
15
|
+
// Try to read SQLITE_PATH from config.json
|
|
16
|
+
if (fs.existsSync(configPath)) {
|
|
14
17
|
try {
|
|
15
|
-
fs.
|
|
16
|
-
|
|
18
|
+
const configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
19
|
+
if (configData.SQLITE_PATH) {
|
|
20
|
+
sqlitePath = path.isAbsolute(configData.SQLITE_PATH)
|
|
21
|
+
? configData.SQLITE_PATH
|
|
22
|
+
: path.join(homeDir, configData.SQLITE_PATH);
|
|
23
|
+
}
|
|
17
24
|
} catch (e) {
|
|
18
|
-
console.error(`Failed to
|
|
25
|
+
console.error(`Failed to read config.json: ${e}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Remove launchd agent if exists (macOS)
|
|
30
|
+
const plistName = 'com.omnikey.daemon.plist';
|
|
31
|
+
const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', plistName);
|
|
32
|
+
if (fs.existsSync(plistPath)) {
|
|
33
|
+
try {
|
|
34
|
+
execSync(`launchctl unload "${plistPath}"`);
|
|
35
|
+
fs.rmSync(plistPath);
|
|
36
|
+
console.log(`Removed launchd agent: ${plistPath}`);
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error(`Failed to remove launchd agent: ${e}`);
|
|
19
39
|
}
|
|
20
40
|
} else {
|
|
21
|
-
console.log(`
|
|
41
|
+
console.log(`Launchd agent does not exist: ${plistPath}`);
|
|
22
42
|
}
|
|
23
43
|
|
|
24
44
|
// Remove SQLite database
|
|
@@ -32,4 +52,16 @@ export function removeConfigAndDb() {
|
|
|
32
52
|
} else {
|
|
33
53
|
console.log(`SQLite database does not exist: ${sqlitePath}`);
|
|
34
54
|
}
|
|
55
|
+
|
|
56
|
+
// Remove .omnikey directory
|
|
57
|
+
if (fs.existsSync(configDir)) {
|
|
58
|
+
try {
|
|
59
|
+
fs.rmSync(configDir, { recursive: true, force: true });
|
|
60
|
+
console.log(`Removed config directory: ${configDir}`);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error(`Failed to remove config directory: ${e}`);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
console.log(`Config directory does not exist: ${configDir}`);
|
|
66
|
+
}
|
|
35
67
|
}
|