forkit-connect 0.1.22 → 0.1.23
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/assets/connect-notifier-512.png +0 -0
- package/dist/cli.js +108 -7
- package/dist/v1/native-shell.d.ts +23 -0
- package/dist/v1/native-shell.js +170 -0
- package/dist/v1/service.js +164 -8
- package/dist/v1/startup.d.ts +12 -0
- package/dist/v1/startup.js +229 -0
- package/package.json +3 -1
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ const daemon_1 = require("./v1/daemon");
|
|
|
13
13
|
const service_1 = require("./v1/service");
|
|
14
14
|
const discovery_1 = require("./v1/discovery");
|
|
15
15
|
const heartbeat_1 = require("./v1/heartbeat");
|
|
16
|
+
const startup_1 = require("./v1/startup");
|
|
16
17
|
const runtime_activity_1 = require("./v1/runtime-activity");
|
|
17
18
|
const runtime_editor_activity_1 = require("./v1/runtime-editor-activity");
|
|
18
19
|
const runtime_observation_runner_1 = require("./v1/runtime-observation-runner");
|
|
@@ -81,6 +82,7 @@ const PUBLIC_COMMANDS = [
|
|
|
81
82
|
['login', 'Link this device to your Forkit.dev account'],
|
|
82
83
|
['logout', 'Remove the stored Forkit.dev session from this device'],
|
|
83
84
|
['status', 'Show account, scope, daemon, and queue status'],
|
|
85
|
+
['startup', 'Enable, disable, or inspect CLI startup on login'],
|
|
84
86
|
['changes', 'View all collected local changes and queued sync items'],
|
|
85
87
|
['start', 'Open the interactive launcher or start foreground sync'],
|
|
86
88
|
['stop', 'Stop the local Connect daemon'],
|
|
@@ -117,14 +119,28 @@ const ADVANCED_COMMAND_GROUPS = [
|
|
|
117
119
|
['notify', 'Notification preview and delivery controls'],
|
|
118
120
|
];
|
|
119
121
|
function usage() {
|
|
120
|
-
printCliHeader('CLI', '
|
|
121
|
-
console.log(cliKeyLine('
|
|
122
|
-
console.log(cliKeyLine('
|
|
122
|
+
printCliHeader('CLI', 'Local AI discovery, review, and registration from your terminal.');
|
|
123
|
+
console.log(cliKeyLine('command', 'forkit-connect <command> [options]'));
|
|
124
|
+
console.log(cliKeyLine('always on', 'forkit-connect startup enable'));
|
|
125
|
+
console.log(cliKeyLine('review', 'forkit-connect inbox'));
|
|
123
126
|
console.log(cliKeyLine('runtime', 'forkit-connect runtime <register|review|status>'));
|
|
124
|
-
printCliSection('
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
printCliSection('Start Here');
|
|
128
|
+
console.log(cliKeyLine('login', 'Connect this device to your Forkit.dev account'));
|
|
129
|
+
console.log(cliKeyLine('scan', 'Detect local models, runtimes, and agents'));
|
|
130
|
+
console.log(cliKeyLine('inbox', 'Review what needs action'));
|
|
131
|
+
console.log(cliKeyLine('startup', 'Keep Connect running from sign-in'));
|
|
132
|
+
printCliSection('Daily');
|
|
133
|
+
console.log(cliKeyLine('status', 'See account, queue, and daemon state'));
|
|
134
|
+
console.log(cliKeyLine('start', 'Open the interactive local console'));
|
|
135
|
+
console.log(cliKeyLine('sync', 'Flush queued local metadata'));
|
|
136
|
+
console.log(cliKeyLine('stop', 'Stop the background daemon'));
|
|
137
|
+
printCliSection('Governed');
|
|
138
|
+
console.log(cliKeyLine('workspace', 'Optional workspace and project scope'));
|
|
139
|
+
console.log(cliKeyLine('register', 'Register ready local models'));
|
|
140
|
+
console.log(cliKeyLine('runtime', 'Register or review local runtimes'));
|
|
141
|
+
printCliSection('Safety');
|
|
142
|
+
console.log(cliKeyLine('ignore', 'Deny one detected local model on this device'));
|
|
143
|
+
console.log(cliKeyLine('doctor', 'Check notifications, storage, and runtime wiring'));
|
|
128
144
|
printCliSection('Flags');
|
|
129
145
|
console.log(cliKeyLine('--json', 'Machine-readable output when supported'));
|
|
130
146
|
console.log(cliKeyLine('--all-ready', 'Register every ready local model in the current scope'));
|
|
@@ -2130,6 +2146,7 @@ function printPublicStatusOverview(status) {
|
|
|
2130
2146
|
console.log(cliKeyLine('device', status.device_paired ? 'paired' : 'approval pending'));
|
|
2131
2147
|
console.log(cliKeyLine('scope', formatCliScopeLabel(status.workspace_id, status.project_id)));
|
|
2132
2148
|
console.log(cliKeyLine('daemon', status.daemon_status));
|
|
2149
|
+
console.log(cliKeyLine('background', status.daemon_status === 'running' ? 'always on' : 'start required'));
|
|
2133
2150
|
console.log(cliKeyLine('privacy', status.privacy_mode));
|
|
2134
2151
|
console.log(cliKeyLine('inventory', joinCliSummary([
|
|
2135
2152
|
formatCliCompactCount(status.models_discovered, 'model'),
|
|
@@ -2150,6 +2167,47 @@ function printPublicStatusOverview(status) {
|
|
|
2150
2167
|
console.log(cliKeyLine('warning', 'Local governed scope exists, but login is still required.'));
|
|
2151
2168
|
}
|
|
2152
2169
|
}
|
|
2170
|
+
function formatStartupSummary(status) {
|
|
2171
|
+
if (!status.supported)
|
|
2172
|
+
return 'not supported';
|
|
2173
|
+
if (status.enabled === true)
|
|
2174
|
+
return 'enabled';
|
|
2175
|
+
if (status.enabled === false)
|
|
2176
|
+
return 'disabled';
|
|
2177
|
+
return 'unknown';
|
|
2178
|
+
}
|
|
2179
|
+
function printStartupStatusLine(status) {
|
|
2180
|
+
console.log(cliKeyLine('startup', formatStartupSummary(status)));
|
|
2181
|
+
}
|
|
2182
|
+
function printPublicStartupStatus(status) {
|
|
2183
|
+
const enabled = status.enabled === true;
|
|
2184
|
+
const platform = status.mode === 'launch_agent'
|
|
2185
|
+
? 'macOS LaunchAgent'
|
|
2186
|
+
: status.mode === 'registry_run'
|
|
2187
|
+
? 'Windows sign-in registry'
|
|
2188
|
+
: status.mode === 'systemd_user'
|
|
2189
|
+
? 'Linux user service'
|
|
2190
|
+
: 'not available';
|
|
2191
|
+
printCliHeader('Startup', 'Keep Forkit Connect running from sign-in without a tray app.');
|
|
2192
|
+
console.log(cliKeyLine('auto start', enabled ? 'on' : status.enabled === false ? 'off' : 'unknown'));
|
|
2193
|
+
console.log(cliKeyLine('behavior', enabled
|
|
2194
|
+
? 'Forkit Connect launches its background daemon when you sign in.'
|
|
2195
|
+
: 'Forkit Connect starts only when you run it manually.'));
|
|
2196
|
+
console.log(cliKeyLine('platform', platform));
|
|
2197
|
+
console.log(cliKeyLine('next', enabled ? 'forkit-connect startup disable' : 'forkit-connect startup enable'));
|
|
2198
|
+
if (hasFlag('--advanced-help') && status.configPath) {
|
|
2199
|
+
console.log(cliKeyLine('config', status.configPath));
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
function getNotificationReadiness() {
|
|
2203
|
+
if (process.platform === 'darwin') {
|
|
2204
|
+
return 'Forkit Connect click-through ready';
|
|
2205
|
+
}
|
|
2206
|
+
if (process.platform === 'win32') {
|
|
2207
|
+
return 'native Windows toasts ready';
|
|
2208
|
+
}
|
|
2209
|
+
return 'native desktop alerts when a GUI session is available';
|
|
2210
|
+
}
|
|
2153
2211
|
function getOtherReadyCount(readyToConnectCount, draftFirstCount) {
|
|
2154
2212
|
return Math.max(0, readyToConnectCount - draftFirstCount);
|
|
2155
2213
|
}
|
|
@@ -2630,6 +2688,7 @@ async function run() {
|
|
|
2630
2688
|
const runPublicConnectStatus = async () => {
|
|
2631
2689
|
const sessionState = await checkBackendSessionState(service);
|
|
2632
2690
|
const secureStorage = service.getCredentialStoreStatus();
|
|
2691
|
+
const startupStatus = (0, startup_1.getCliStartupStatus)();
|
|
2633
2692
|
if (service.readSessionRef()) {
|
|
2634
2693
|
await withTimeout(service.refreshEffectiveBinding(), STATUS_BINDING_TIMEOUT_MS, undefined);
|
|
2635
2694
|
}
|
|
@@ -2655,6 +2714,10 @@ async function run() {
|
|
|
2655
2714
|
session_truth: accountTrusted ? 'account_verified_or_offline' : 'local_scope_cached_login_required',
|
|
2656
2715
|
local_scope_cached: !accountTrusted && localScopeCached,
|
|
2657
2716
|
binding_truth: accountTrusted ? 'account_binding_active' : 'account_login_required',
|
|
2717
|
+
startup_on_login: startupStatus,
|
|
2718
|
+
notifications: {
|
|
2719
|
+
readiness: getNotificationReadiness(),
|
|
2720
|
+
},
|
|
2658
2721
|
secure_storage: {
|
|
2659
2722
|
backend: secureStorage.backend,
|
|
2660
2723
|
available: secureStorage.available,
|
|
@@ -2670,8 +2733,28 @@ async function run() {
|
|
|
2670
2733
|
if (!secureStorage.available || secureStorage.plaintextFallbackActive) {
|
|
2671
2734
|
console.log(cliKeyLine('secure note', secureStorage.detail));
|
|
2672
2735
|
}
|
|
2736
|
+
console.log(cliKeyLine('notifications', getNotificationReadiness()));
|
|
2737
|
+
printStartupStatusLine(startupStatus);
|
|
2673
2738
|
printPublicStatusGuidance(displayOverview, sessionState);
|
|
2674
2739
|
};
|
|
2740
|
+
const runPublicStartupStatus = () => {
|
|
2741
|
+
const startupStatus = (0, startup_1.getCliStartupStatus)();
|
|
2742
|
+
if (hasFlag('--json')) {
|
|
2743
|
+
printJson(startupStatus);
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
printPublicStartupStatus(startupStatus);
|
|
2747
|
+
};
|
|
2748
|
+
const runPublicStartupEnable = () => {
|
|
2749
|
+
const startupStatus = (0, startup_1.enableCliStartup)(process.execPath, __filename);
|
|
2750
|
+
printPublicStartupStatus(startupStatus);
|
|
2751
|
+
console.log('[forkit-connect] CLI startup on login is enabled. The background daemon will come up when your session starts.');
|
|
2752
|
+
};
|
|
2753
|
+
const runPublicStartupDisable = () => {
|
|
2754
|
+
const startupStatus = (0, startup_1.disableCliStartup)();
|
|
2755
|
+
printPublicStartupStatus(startupStatus);
|
|
2756
|
+
console.log('[forkit-connect] CLI startup on login is disabled. Use forkit-connect stop if you also want to stop the daemon right now.');
|
|
2757
|
+
};
|
|
2675
2758
|
const runPublicConnectInbox = async () => {
|
|
2676
2759
|
const forceRefresh = hasFlag('--refresh');
|
|
2677
2760
|
const inbox = service.getSmartRegistrationInbox({
|
|
@@ -4934,6 +5017,24 @@ async function run() {
|
|
|
4934
5017
|
await runPublicConnectStatus();
|
|
4935
5018
|
return;
|
|
4936
5019
|
}
|
|
5020
|
+
if (command === 'startup') {
|
|
5021
|
+
const subcommand = args[1] || 'status';
|
|
5022
|
+
if (subcommand === 'status') {
|
|
5023
|
+
runPublicStartupStatus();
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5026
|
+
if (subcommand === 'enable') {
|
|
5027
|
+
runPublicStartupEnable();
|
|
5028
|
+
return;
|
|
5029
|
+
}
|
|
5030
|
+
if (subcommand === 'disable') {
|
|
5031
|
+
runPublicStartupDisable();
|
|
5032
|
+
return;
|
|
5033
|
+
}
|
|
5034
|
+
showUsage();
|
|
5035
|
+
process.exitCode = 1;
|
|
5036
|
+
return;
|
|
5037
|
+
}
|
|
4937
5038
|
if (command === 'changes') {
|
|
4938
5039
|
runPublicCollectedChanges();
|
|
4939
5040
|
return;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReleaseCheckResult } from './update';
|
|
2
|
+
export interface NativeShellStatus {
|
|
3
|
+
supported: boolean;
|
|
4
|
+
installed: boolean;
|
|
5
|
+
platform: 'macos' | 'windows' | 'linux';
|
|
6
|
+
installationPath: string | null;
|
|
7
|
+
trayAvailable: boolean;
|
|
8
|
+
startupAvailable: boolean;
|
|
9
|
+
directInstallerAvailable: boolean;
|
|
10
|
+
downloadUrl: string | null;
|
|
11
|
+
releaseNotesUrl: string | null;
|
|
12
|
+
note: string;
|
|
13
|
+
}
|
|
14
|
+
export interface NativeShellOpenResult {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
opened: 'installed' | 'download';
|
|
17
|
+
installationPath: string | null;
|
|
18
|
+
downloadUrl: string | null;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function getNativeShellStatus(updateCheck?: ReleaseCheckResult): Promise<NativeShellStatus>;
|
|
22
|
+
export declare function openNativeShell(updateCheck?: ReleaseCheckResult): Promise<NativeShellOpenResult>;
|
|
23
|
+
//# sourceMappingURL=native-shell.d.ts.map
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getNativeShellStatus = getNativeShellStatus;
|
|
7
|
+
exports.openNativeShell = openNativeShell;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const node_child_process_1 = require("node:child_process");
|
|
12
|
+
const update_1 = require("./update");
|
|
13
|
+
const CONNECT_DESKTOP_FALLBACK_URL = 'https://www.forkit.dev/connect';
|
|
14
|
+
function normalizePlatform() {
|
|
15
|
+
if (process.platform === 'darwin')
|
|
16
|
+
return 'macos';
|
|
17
|
+
if (process.platform === 'win32')
|
|
18
|
+
return 'windows';
|
|
19
|
+
return 'linux';
|
|
20
|
+
}
|
|
21
|
+
function getCandidatePaths(platform) {
|
|
22
|
+
const home = node_os_1.default.homedir();
|
|
23
|
+
if (platform === 'macos') {
|
|
24
|
+
return [
|
|
25
|
+
'/Applications/Forkit Connect.app',
|
|
26
|
+
node_path_1.default.join(home, 'Applications', 'Forkit Connect.app'),
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
if (platform === 'windows') {
|
|
30
|
+
const localAppData = process.env.LOCALAPPDATA || node_path_1.default.join(home, 'AppData', 'Local');
|
|
31
|
+
const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
|
|
32
|
+
const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)';
|
|
33
|
+
return [
|
|
34
|
+
node_path_1.default.join(localAppData, 'Programs', 'Forkit Connect', 'Forkit Connect.exe'),
|
|
35
|
+
node_path_1.default.join(programFiles, 'Forkit Connect', 'Forkit Connect.exe'),
|
|
36
|
+
node_path_1.default.join(programFilesX86, 'Forkit Connect', 'Forkit Connect.exe'),
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
return [
|
|
40
|
+
node_path_1.default.join(home, '.local', 'bin', 'forkit-connect-desktop'),
|
|
41
|
+
node_path_1.default.join(home, '.local', 'share', 'Forkit Connect', 'Forkit Connect.AppImage'),
|
|
42
|
+
'/usr/local/bin/forkit-connect-desktop',
|
|
43
|
+
'/opt/Forkit Connect/forkit-connect-desktop',
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function findInstalledPath(platform) {
|
|
47
|
+
for (const candidate of getCandidatePaths(platform)) {
|
|
48
|
+
try {
|
|
49
|
+
if (node_fs_1.default.existsSync(candidate)) {
|
|
50
|
+
return candidate;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function parseVersion(version) {
|
|
60
|
+
const cleaned = String(version || '').trim().replace(/^v/i, '').split('-')[0] || '0.0.0';
|
|
61
|
+
const [major, minor, patch] = cleaned.split('.').map((value) => Number.parseInt(value || '0', 10));
|
|
62
|
+
return [major || 0, minor || 0, patch || 0];
|
|
63
|
+
}
|
|
64
|
+
function compareVersions(left, right) {
|
|
65
|
+
const [leftMajor, leftMinor, leftPatch] = parseVersion(left);
|
|
66
|
+
const [rightMajor, rightMinor, rightPatch] = parseVersion(right);
|
|
67
|
+
if (leftMajor !== rightMajor)
|
|
68
|
+
return leftMajor - rightMajor;
|
|
69
|
+
if (leftMinor !== rightMinor)
|
|
70
|
+
return leftMinor - rightMinor;
|
|
71
|
+
return leftPatch - rightPatch;
|
|
72
|
+
}
|
|
73
|
+
function buildDownloadUrl(updateCheck) {
|
|
74
|
+
if (!updateCheck.ok) {
|
|
75
|
+
return CONNECT_DESKTOP_FALLBACK_URL;
|
|
76
|
+
}
|
|
77
|
+
if (compareVersions(updateCheck.manifest.latestVersion, updateCheck.currentVersion) < 0) {
|
|
78
|
+
return CONNECT_DESKTOP_FALLBACK_URL;
|
|
79
|
+
}
|
|
80
|
+
return updateCheck.downloadUrl || updateCheck.manifest.releaseNotesUrl || CONNECT_DESKTOP_FALLBACK_URL;
|
|
81
|
+
}
|
|
82
|
+
function hasDirectInstaller(updateCheck) {
|
|
83
|
+
if (!updateCheck.ok)
|
|
84
|
+
return false;
|
|
85
|
+
if (compareVersions(updateCheck.manifest.latestVersion, updateCheck.currentVersion) < 0) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return Boolean(updateCheck.downloadUrl);
|
|
89
|
+
}
|
|
90
|
+
function isInstallerOnlyRelease(updateCheck) {
|
|
91
|
+
if (!updateCheck.ok)
|
|
92
|
+
return false;
|
|
93
|
+
const manifest = updateCheck.manifest;
|
|
94
|
+
const integrity = manifest.integrity;
|
|
95
|
+
if (!integrity || typeof integrity !== 'object')
|
|
96
|
+
return false;
|
|
97
|
+
return integrity.installerOnly === true;
|
|
98
|
+
}
|
|
99
|
+
async function getNativeShellStatus(updateCheck) {
|
|
100
|
+
const platform = normalizePlatform();
|
|
101
|
+
const installationPath = findInstalledPath(platform);
|
|
102
|
+
const installed = Boolean(installationPath);
|
|
103
|
+
const resolvedUpdateCheck = updateCheck ?? await (0, update_1.checkForUpdates)();
|
|
104
|
+
const directInstallerAvailable = hasDirectInstaller(resolvedUpdateCheck);
|
|
105
|
+
const installerOnlyRelease = isInstallerOnlyRelease(resolvedUpdateCheck);
|
|
106
|
+
const downloadUrl = buildDownloadUrl(resolvedUpdateCheck);
|
|
107
|
+
const releaseNotesUrl = resolvedUpdateCheck.ok ? resolvedUpdateCheck.manifest.releaseNotesUrl : CONNECT_DESKTOP_FALLBACK_URL;
|
|
108
|
+
return {
|
|
109
|
+
supported: true,
|
|
110
|
+
installed,
|
|
111
|
+
platform,
|
|
112
|
+
installationPath,
|
|
113
|
+
trayAvailable: installed,
|
|
114
|
+
startupAvailable: installed,
|
|
115
|
+
directInstallerAvailable,
|
|
116
|
+
downloadUrl,
|
|
117
|
+
releaseNotesUrl,
|
|
118
|
+
note: installed
|
|
119
|
+
? 'Desktop app installed. Tray or menu-bar controls and launch at sign-in are handled there.'
|
|
120
|
+
: installerOnlyRelease
|
|
121
|
+
? 'Install the desktop app to get tray or menu-bar controls and launch at sign-in. In-app updates are not published for this release yet.'
|
|
122
|
+
: directInstallerAvailable
|
|
123
|
+
? 'Install the desktop app to get tray or menu-bar controls, launch at sign-in, and in-app updates.'
|
|
124
|
+
: 'The desktop app installer is not published for this platform yet. Use the Connect downloads page for the current release.',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function spawnDetached(command, args, cwd) {
|
|
128
|
+
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
129
|
+
detached: true,
|
|
130
|
+
stdio: 'ignore',
|
|
131
|
+
windowsHide: true,
|
|
132
|
+
...(cwd ? { cwd } : {}),
|
|
133
|
+
});
|
|
134
|
+
child.unref();
|
|
135
|
+
}
|
|
136
|
+
function openInstalledShell(status) {
|
|
137
|
+
if (!status.installationPath) {
|
|
138
|
+
throw new Error('native_shell_missing');
|
|
139
|
+
}
|
|
140
|
+
if (status.platform === 'macos') {
|
|
141
|
+
spawnDetached('open', [status.installationPath]);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (status.platform === 'windows') {
|
|
145
|
+
spawnDetached(status.installationPath, [], node_path_1.default.dirname(status.installationPath));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
spawnDetached(status.installationPath, [], node_path_1.default.dirname(status.installationPath));
|
|
149
|
+
}
|
|
150
|
+
async function openNativeShell(updateCheck) {
|
|
151
|
+
const status = await getNativeShellStatus(updateCheck);
|
|
152
|
+
if (status.installed) {
|
|
153
|
+
openInstalledShell(status);
|
|
154
|
+
return {
|
|
155
|
+
ok: true,
|
|
156
|
+
opened: 'installed',
|
|
157
|
+
installationPath: status.installationPath,
|
|
158
|
+
downloadUrl: status.downloadUrl,
|
|
159
|
+
message: 'Opening the native Forkit Connect shell.',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
opened: 'download',
|
|
165
|
+
installationPath: null,
|
|
166
|
+
downloadUrl: status.downloadUrl,
|
|
167
|
+
message: 'Install the Forkit Connect desktop app to enable tray or menu-bar controls and launch at sign-in.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=native-shell.js.map
|
package/dist/v1/service.js
CHANGED
|
@@ -173,6 +173,33 @@ function notificationTargetUrl(candidate) {
|
|
|
173
173
|
}
|
|
174
174
|
return `${base}/?${params.toString()}`;
|
|
175
175
|
}
|
|
176
|
+
function notificationTargetCommand(candidate) {
|
|
177
|
+
const targetArgs = (() => {
|
|
178
|
+
if (!candidate) {
|
|
179
|
+
return ['inbox'];
|
|
180
|
+
}
|
|
181
|
+
if (candidate.suggested_action === 'reconnect_account' || candidate.type === 'credential_reconnect_needed') {
|
|
182
|
+
return ['login'];
|
|
183
|
+
}
|
|
184
|
+
if (candidate.suggested_action === 'sync_c2' || candidate.type === 'c2_sync_pending') {
|
|
185
|
+
return ['sync'];
|
|
186
|
+
}
|
|
187
|
+
if (candidate.suggested_action === 'view_pulse_history') {
|
|
188
|
+
return ['changes'];
|
|
189
|
+
}
|
|
190
|
+
return ['inbox'];
|
|
191
|
+
})();
|
|
192
|
+
const currentScriptPath = process.argv[1] && node_path_1.default.isAbsolute(process.argv[1])
|
|
193
|
+
? process.argv[1]
|
|
194
|
+
: process.argv[1]
|
|
195
|
+
? node_path_1.default.resolve(process.cwd(), process.argv[1])
|
|
196
|
+
: null;
|
|
197
|
+
if (currentScriptPath && node_fs_1.default.existsSync(currentScriptPath)) {
|
|
198
|
+
const quote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
199
|
+
return [quote(process.execPath), quote(currentScriptPath), ...targetArgs.map(quote)].join(' ');
|
|
200
|
+
}
|
|
201
|
+
return `forkit-connect ${targetArgs.join(' ')}`;
|
|
202
|
+
}
|
|
176
203
|
function hasLinuxGuiSession() {
|
|
177
204
|
return Boolean(normalizeSessionReference(process.env.DISPLAY)
|
|
178
205
|
|| normalizeSessionReference(process.env.WAYLAND_DISPLAY)
|
|
@@ -186,6 +213,129 @@ function resolveTerminalNotifierPath() {
|
|
|
186
213
|
const resolved = String(notifierPath.stdout || '').trim();
|
|
187
214
|
return resolved || null;
|
|
188
215
|
}
|
|
216
|
+
function resolveBundledTerminalNotifierBinary() {
|
|
217
|
+
try {
|
|
218
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
219
|
+
const notifierPackageJson = require.resolve('node-notifier/package.json');
|
|
220
|
+
const candidate = node_path_1.default.join(node_path_1.default.dirname(notifierPackageJson), 'vendor', 'mac.noindex', 'terminal-notifier.app', 'Contents', 'MacOS', 'terminal-notifier');
|
|
221
|
+
return node_fs_1.default.existsSync(candidate) ? candidate : null;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function resolveBrandedNotifierIconSource() {
|
|
228
|
+
const candidate = node_path_1.default.resolve(__dirname, '..', '..', 'assets', 'connect-notifier-512.png');
|
|
229
|
+
return node_fs_1.default.existsSync(candidate) ? candidate : null;
|
|
230
|
+
}
|
|
231
|
+
function ensureBrandedMacNotifierIcon(helperApp) {
|
|
232
|
+
const sourcePng = resolveBrandedNotifierIconSource();
|
|
233
|
+
if (!sourcePng) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const resourcesDir = node_path_1.default.join(helperApp, 'Contents', 'Resources');
|
|
237
|
+
const iconTarget = node_path_1.default.join(resourcesDir, 'Terminal.icns');
|
|
238
|
+
const iconMarker = node_path_1.default.join(resourcesDir, '.forkit-notifier-icon-v1');
|
|
239
|
+
if (node_fs_1.default.existsSync(iconMarker) && node_fs_1.default.existsSync(iconTarget)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const iconsetDir = node_path_1.default.join(resourcesDir, 'ForkitConnect.iconset');
|
|
243
|
+
node_fs_1.default.rmSync(iconsetDir, { recursive: true, force: true });
|
|
244
|
+
node_fs_1.default.mkdirSync(iconsetDir, { recursive: true });
|
|
245
|
+
const variants = [
|
|
246
|
+
{ file: 'icon_16x16.png', size: 16 },
|
|
247
|
+
{ file: 'icon_16x16@2x.png', size: 32 },
|
|
248
|
+
{ file: 'icon_32x32.png', size: 32 },
|
|
249
|
+
{ file: 'icon_32x32@2x.png', size: 64 },
|
|
250
|
+
{ file: 'icon_128x128.png', size: 128 },
|
|
251
|
+
{ file: 'icon_128x128@2x.png', size: 256 },
|
|
252
|
+
{ file: 'icon_256x256.png', size: 256 },
|
|
253
|
+
{ file: 'icon_256x256@2x.png', size: 512 },
|
|
254
|
+
{ file: 'icon_512x512.png', size: 512 },
|
|
255
|
+
];
|
|
256
|
+
try {
|
|
257
|
+
for (const variant of variants) {
|
|
258
|
+
const outputPath = node_path_1.default.join(iconsetDir, variant.file);
|
|
259
|
+
const result = (0, node_child_process_1.spawnSync)('/usr/bin/sips', ['-z', String(variant.size), String(variant.size), sourcePng, '--out', outputPath], {
|
|
260
|
+
stdio: 'ignore',
|
|
261
|
+
});
|
|
262
|
+
if (result.status !== 0) {
|
|
263
|
+
throw new Error('icon_resize_failed');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
node_fs_1.default.copyFileSync(sourcePng, node_path_1.default.join(iconsetDir, 'icon_512x512@2x.png'));
|
|
267
|
+
const buildResult = (0, node_child_process_1.spawnSync)('/usr/bin/iconutil', ['-c', 'icns', iconsetDir, '-o', iconTarget], {
|
|
268
|
+
stdio: 'ignore',
|
|
269
|
+
});
|
|
270
|
+
if (buildResult.status !== 0) {
|
|
271
|
+
throw new Error('iconutil_failed');
|
|
272
|
+
}
|
|
273
|
+
node_fs_1.default.writeFileSync(iconMarker, 'forkit-connect-notifier-icon-v1\n', 'utf8');
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
node_fs_1.default.rmSync(iconsetDir, { recursive: true, force: true });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function notificationExecuteCommand(candidate) {
|
|
283
|
+
if (process.platform !== 'darwin') {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const targetCommand = notificationTargetCommand(candidate);
|
|
287
|
+
const escapedCommand = `${targetCommand}; exec "\${SHELL:-/bin/zsh}" -l`
|
|
288
|
+
.replace(/\\/g, '\\\\')
|
|
289
|
+
.replace(/"/g, '\\"');
|
|
290
|
+
return [
|
|
291
|
+
'/usr/bin/osascript',
|
|
292
|
+
`-e 'tell application "Terminal" to activate'`,
|
|
293
|
+
`-e 'tell application "Terminal" to do script "${escapedCommand}"'`,
|
|
294
|
+
].join(' ');
|
|
295
|
+
}
|
|
296
|
+
function resolveBrandedMacNotifierBinary() {
|
|
297
|
+
if (process.platform !== 'darwin') {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
const bundledBinary = resolveBundledTerminalNotifierBinary();
|
|
301
|
+
if (!bundledBinary) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
const sourceApp = node_path_1.default.resolve(bundledBinary, '..', '..', '..');
|
|
305
|
+
const helperApp = node_path_1.default.join(node_os_1.default.homedir(), '.forkit-connect', 'vendor', 'Forkit Connect.app');
|
|
306
|
+
const helperBinary = node_path_1.default.join(helperApp, 'Contents', 'MacOS', 'terminal-notifier');
|
|
307
|
+
const helperPlist = node_path_1.default.join(helperApp, 'Contents', 'Info.plist');
|
|
308
|
+
const isAlreadyBranded = () => {
|
|
309
|
+
if (!node_fs_1.default.existsSync(helperBinary) || !node_fs_1.default.existsSync(helperPlist)) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const result = (0, node_child_process_1.spawnSync)('plutil', ['-extract', 'CFBundleIdentifier', 'raw', '-o', '-', helperPlist], {
|
|
314
|
+
encoding: 'utf8',
|
|
315
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
316
|
+
});
|
|
317
|
+
return result.status === 0 && String(result.stdout || '').trim() === 'dev.forkit.connect.notifications';
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
if (!isAlreadyBranded()) {
|
|
324
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(helperApp), { recursive: true });
|
|
325
|
+
node_fs_1.default.rmSync(helperApp, { recursive: true, force: true });
|
|
326
|
+
node_fs_1.default.cpSync(sourceApp, helperApp, { recursive: true });
|
|
327
|
+
const replacements = [
|
|
328
|
+
['CFBundleIdentifier', 'dev.forkit.connect.notifications'],
|
|
329
|
+
['CFBundleName', 'Forkit Connect'],
|
|
330
|
+
['CFBundleDisplayName', 'Forkit Connect'],
|
|
331
|
+
];
|
|
332
|
+
for (const [key, value] of replacements) {
|
|
333
|
+
(0, node_child_process_1.spawnSync)('plutil', ['-replace', key, '-string', value, helperPlist], { stdio: 'ignore' });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
ensureBrandedMacNotifierIcon(helperApp);
|
|
337
|
+
return node_fs_1.default.existsSync(helperBinary) ? helperBinary : null;
|
|
338
|
+
}
|
|
189
339
|
function defaultNotificationSender(title, message, candidate) {
|
|
190
340
|
if (process.platform === 'linux') {
|
|
191
341
|
if (!hasLinuxGuiSession()) {
|
|
@@ -210,15 +360,21 @@ function defaultNotificationSender(title, message, candidate) {
|
|
|
210
360
|
}
|
|
211
361
|
}
|
|
212
362
|
if (process.platform === 'darwin') {
|
|
213
|
-
const
|
|
214
|
-
const resolvedNotifier = resolveTerminalNotifierPath();
|
|
363
|
+
const resolvedNotifier = resolveBrandedMacNotifierBinary() ?? resolveTerminalNotifierPath();
|
|
215
364
|
if (resolvedNotifier) {
|
|
216
|
-
const
|
|
217
|
-
const
|
|
365
|
+
const executeCommand = notificationExecuteCommand(candidate);
|
|
366
|
+
const args = [
|
|
218
367
|
'-title', title,
|
|
368
|
+
'-subtitle', 'Forkit Connect',
|
|
219
369
|
'-message', message,
|
|
220
|
-
'-execute', openCommand,
|
|
221
370
|
'-group', 'forkit-connect',
|
|
371
|
+
'-sender', 'dev.forkit.connect.notifications',
|
|
372
|
+
];
|
|
373
|
+
if (executeCommand) {
|
|
374
|
+
args.push('-execute', executeCommand);
|
|
375
|
+
}
|
|
376
|
+
const result = (0, node_child_process_1.spawnSync)(resolvedNotifier, [
|
|
377
|
+
...args,
|
|
222
378
|
], { stdio: 'ignore' });
|
|
223
379
|
if (result.status === 0) {
|
|
224
380
|
return true;
|
|
@@ -8925,13 +9081,13 @@ class ConnectV1Service {
|
|
|
8925
9081
|
: `Unavailable at ${ollama.endpoint}: ${ollama.error ?? 'unknown_error'}`,
|
|
8926
9082
|
});
|
|
8927
9083
|
if (process.platform === 'darwin') {
|
|
8928
|
-
const notifierPath = resolveTerminalNotifierPath();
|
|
9084
|
+
const notifierPath = resolveBrandedMacNotifierBinary() ?? resolveTerminalNotifierPath();
|
|
8929
9085
|
checks.push({
|
|
8930
9086
|
name: 'desktop_notifications',
|
|
8931
9087
|
status: notifierPath ? 'PASS' : 'WARN',
|
|
8932
9088
|
details: notifierPath
|
|
8933
|
-
?
|
|
8934
|
-
: '
|
|
9089
|
+
? 'Forkit Connect native notifications are ready with click-through support.'
|
|
9090
|
+
: 'Forkit Connect notifications are not ready yet on this Mac.',
|
|
8935
9091
|
});
|
|
8936
9092
|
}
|
|
8937
9093
|
const sessionRefSource = this.getSessionRefSource();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CliStartupStatus {
|
|
2
|
+
supported: boolean;
|
|
3
|
+
platform: 'macos' | 'windows' | 'linux';
|
|
4
|
+
enabled: boolean | null;
|
|
5
|
+
mode: 'launch_agent' | 'registry_run' | 'systemd_user' | 'unsupported';
|
|
6
|
+
configPath: string | null;
|
|
7
|
+
note: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function getCliStartupStatus(): CliStartupStatus;
|
|
10
|
+
export declare function enableCliStartup(processExecPath: string, cliPath: string): CliStartupStatus;
|
|
11
|
+
export declare function disableCliStartup(): CliStartupStatus;
|
|
12
|
+
//# sourceMappingURL=startup.d.ts.map
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getCliStartupStatus = getCliStartupStatus;
|
|
7
|
+
exports.enableCliStartup = enableCliStartup;
|
|
8
|
+
exports.disableCliStartup = disableCliStartup;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const node_child_process_1 = require("node:child_process");
|
|
13
|
+
function normalizePlatform() {
|
|
14
|
+
if (process.platform === 'darwin')
|
|
15
|
+
return 'macos';
|
|
16
|
+
if (process.platform === 'win32')
|
|
17
|
+
return 'windows';
|
|
18
|
+
return 'linux';
|
|
19
|
+
}
|
|
20
|
+
function macLabel() {
|
|
21
|
+
return 'dev.forkit.connect.cli';
|
|
22
|
+
}
|
|
23
|
+
function macPlistPath() {
|
|
24
|
+
return node_path_1.default.join(node_os_1.default.homedir(), 'Library', 'LaunchAgents', `${macLabel()}.plist`);
|
|
25
|
+
}
|
|
26
|
+
function linuxServiceName() {
|
|
27
|
+
return 'forkit-connect.service';
|
|
28
|
+
}
|
|
29
|
+
function linuxServicePath() {
|
|
30
|
+
return node_path_1.default.join(node_os_1.default.homedir(), '.config', 'systemd', 'user', linuxServiceName());
|
|
31
|
+
}
|
|
32
|
+
function windowsRegistryKey() {
|
|
33
|
+
return 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';
|
|
34
|
+
}
|
|
35
|
+
function windowsRegistryValueName() {
|
|
36
|
+
return 'ForkitConnectCLI';
|
|
37
|
+
}
|
|
38
|
+
function launchctlGuiTarget() {
|
|
39
|
+
return `gui/${process.getuid?.() ?? 0}`;
|
|
40
|
+
}
|
|
41
|
+
function quoteWindows(value) {
|
|
42
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
43
|
+
}
|
|
44
|
+
function startupCommand(processExecPath, cliPath) {
|
|
45
|
+
return {
|
|
46
|
+
executable: processExecPath,
|
|
47
|
+
args: [cliPath, 'daemon', 'run-loop'],
|
|
48
|
+
display: `${quoteWindows(processExecPath)} ${quoteWindows(cliPath)} daemon run-loop`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function writeMacPlist(processExecPath, cliPath) {
|
|
52
|
+
const command = startupCommand(processExecPath, cliPath);
|
|
53
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
54
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
55
|
+
<plist version="1.0">
|
|
56
|
+
<dict>
|
|
57
|
+
<key>Label</key>
|
|
58
|
+
<string>${macLabel()}</string>
|
|
59
|
+
<key>ProgramArguments</key>
|
|
60
|
+
<array>
|
|
61
|
+
<string>${command.executable}</string>
|
|
62
|
+
<string>${command.args[0]}</string>
|
|
63
|
+
<string>${command.args[1]}</string>
|
|
64
|
+
<string>${command.args[2]}</string>
|
|
65
|
+
</array>
|
|
66
|
+
<key>RunAtLoad</key>
|
|
67
|
+
<true/>
|
|
68
|
+
<key>KeepAlive</key>
|
|
69
|
+
<true/>
|
|
70
|
+
<key>WorkingDirectory</key>
|
|
71
|
+
<string>${process.cwd()}</string>
|
|
72
|
+
</dict>
|
|
73
|
+
</plist>
|
|
74
|
+
`;
|
|
75
|
+
const plistPath = macPlistPath();
|
|
76
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(plistPath), { recursive: true });
|
|
77
|
+
node_fs_1.default.writeFileSync(plistPath, plist, 'utf8');
|
|
78
|
+
return plistPath;
|
|
79
|
+
}
|
|
80
|
+
function writeLinuxService(processExecPath, cliPath) {
|
|
81
|
+
const command = startupCommand(processExecPath, cliPath);
|
|
82
|
+
const unit = `[Unit]
|
|
83
|
+
Description=Forkit Connect CLI background daemon
|
|
84
|
+
After=default.target
|
|
85
|
+
|
|
86
|
+
[Service]
|
|
87
|
+
Type=simple
|
|
88
|
+
ExecStart=${command.executable} ${command.args.join(' ')}
|
|
89
|
+
Restart=always
|
|
90
|
+
RestartSec=3
|
|
91
|
+
WorkingDirectory=${process.cwd()}
|
|
92
|
+
|
|
93
|
+
[Install]
|
|
94
|
+
WantedBy=default.target
|
|
95
|
+
`;
|
|
96
|
+
const servicePath = linuxServicePath();
|
|
97
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(servicePath), { recursive: true });
|
|
98
|
+
node_fs_1.default.writeFileSync(servicePath, unit, 'utf8');
|
|
99
|
+
return servicePath;
|
|
100
|
+
}
|
|
101
|
+
function getMacStatus() {
|
|
102
|
+
const plistPath = macPlistPath();
|
|
103
|
+
const exists = node_fs_1.default.existsSync(plistPath);
|
|
104
|
+
return {
|
|
105
|
+
supported: true,
|
|
106
|
+
platform: 'macos',
|
|
107
|
+
enabled: exists,
|
|
108
|
+
mode: 'launch_agent',
|
|
109
|
+
configPath: plistPath,
|
|
110
|
+
note: exists
|
|
111
|
+
? 'Forkit Connect CLI will start at sign-in through a LaunchAgent.'
|
|
112
|
+
: 'Forkit Connect CLI is not set to start at sign-in on this Mac.',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function getWindowsStatus() {
|
|
116
|
+
const query = (0, node_child_process_1.spawnSync)('reg', ['query', windowsRegistryKey(), '/v', windowsRegistryValueName()], {
|
|
117
|
+
encoding: 'utf8',
|
|
118
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
119
|
+
});
|
|
120
|
+
const enabled = query.status === 0;
|
|
121
|
+
return {
|
|
122
|
+
supported: true,
|
|
123
|
+
platform: 'windows',
|
|
124
|
+
enabled,
|
|
125
|
+
mode: 'registry_run',
|
|
126
|
+
configPath: windowsRegistryKey(),
|
|
127
|
+
note: enabled
|
|
128
|
+
? 'Forkit Connect CLI will start after sign-in through the Windows Run registry.'
|
|
129
|
+
: 'Forkit Connect CLI is not set to start after sign-in on Windows.',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function getLinuxStatus() {
|
|
133
|
+
const servicePath = linuxServicePath();
|
|
134
|
+
const exists = node_fs_1.default.existsSync(servicePath);
|
|
135
|
+
return {
|
|
136
|
+
supported: true,
|
|
137
|
+
platform: 'linux',
|
|
138
|
+
enabled: exists,
|
|
139
|
+
mode: 'systemd_user',
|
|
140
|
+
configPath: servicePath,
|
|
141
|
+
note: exists
|
|
142
|
+
? 'Forkit Connect CLI will start in the user session through systemd.'
|
|
143
|
+
: 'Forkit Connect CLI is not set to start in the user session on Linux.',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function getCliStartupStatus() {
|
|
147
|
+
const platform = normalizePlatform();
|
|
148
|
+
if (platform === 'macos')
|
|
149
|
+
return getMacStatus();
|
|
150
|
+
if (platform === 'windows')
|
|
151
|
+
return getWindowsStatus();
|
|
152
|
+
if (platform === 'linux')
|
|
153
|
+
return getLinuxStatus();
|
|
154
|
+
return {
|
|
155
|
+
supported: false,
|
|
156
|
+
platform,
|
|
157
|
+
enabled: null,
|
|
158
|
+
mode: 'unsupported',
|
|
159
|
+
configPath: null,
|
|
160
|
+
note: 'Startup management is not available on this platform.',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function enableCliStartup(processExecPath, cliPath) {
|
|
164
|
+
const platform = normalizePlatform();
|
|
165
|
+
if (platform === 'macos') {
|
|
166
|
+
const plistPath = writeMacPlist(processExecPath, cliPath);
|
|
167
|
+
(0, node_child_process_1.spawnSync)('launchctl', ['bootout', launchctlGuiTarget(), plistPath], { stdio: 'ignore' });
|
|
168
|
+
const bootstrap = (0, node_child_process_1.spawnSync)('launchctl', ['bootstrap', launchctlGuiTarget(), plistPath], { stdio: 'ignore' });
|
|
169
|
+
if (bootstrap.status !== 0) {
|
|
170
|
+
throw new Error('cli_startup_enable_failed_macos');
|
|
171
|
+
}
|
|
172
|
+
(0, node_child_process_1.spawnSync)('launchctl', ['kickstart', '-k', `${launchctlGuiTarget()}/${macLabel()}`], { stdio: 'ignore' });
|
|
173
|
+
return getMacStatus();
|
|
174
|
+
}
|
|
175
|
+
if (platform === 'windows') {
|
|
176
|
+
const command = startupCommand(processExecPath, cliPath);
|
|
177
|
+
const add = (0, node_child_process_1.spawnSync)('reg', [
|
|
178
|
+
'add',
|
|
179
|
+
windowsRegistryKey(),
|
|
180
|
+
'/v',
|
|
181
|
+
windowsRegistryValueName(),
|
|
182
|
+
'/t',
|
|
183
|
+
'REG_SZ',
|
|
184
|
+
'/d',
|
|
185
|
+
command.display,
|
|
186
|
+
'/f',
|
|
187
|
+
], { stdio: 'ignore' });
|
|
188
|
+
if (add.status !== 0) {
|
|
189
|
+
throw new Error('cli_startup_enable_failed_windows');
|
|
190
|
+
}
|
|
191
|
+
return getWindowsStatus();
|
|
192
|
+
}
|
|
193
|
+
if (platform === 'linux') {
|
|
194
|
+
const servicePath = writeLinuxService(processExecPath, cliPath);
|
|
195
|
+
const reload = (0, node_child_process_1.spawnSync)('systemctl', ['--user', 'daemon-reload'], { stdio: 'ignore' });
|
|
196
|
+
const enable = (0, node_child_process_1.spawnSync)('systemctl', ['--user', 'enable', '--now', linuxServiceName()], { stdio: 'ignore' });
|
|
197
|
+
if (reload.status !== 0 || enable.status !== 0 || !node_fs_1.default.existsSync(servicePath)) {
|
|
198
|
+
throw new Error('cli_startup_enable_failed_linux');
|
|
199
|
+
}
|
|
200
|
+
return getLinuxStatus();
|
|
201
|
+
}
|
|
202
|
+
throw new Error('cli_startup_unsupported');
|
|
203
|
+
}
|
|
204
|
+
function disableCliStartup() {
|
|
205
|
+
const platform = normalizePlatform();
|
|
206
|
+
if (platform === 'macos') {
|
|
207
|
+
const plistPath = macPlistPath();
|
|
208
|
+
(0, node_child_process_1.spawnSync)('launchctl', ['bootout', launchctlGuiTarget(), plistPath], { stdio: 'ignore' });
|
|
209
|
+
if (node_fs_1.default.existsSync(plistPath)) {
|
|
210
|
+
node_fs_1.default.rmSync(plistPath, { force: true });
|
|
211
|
+
}
|
|
212
|
+
return getMacStatus();
|
|
213
|
+
}
|
|
214
|
+
if (platform === 'windows') {
|
|
215
|
+
(0, node_child_process_1.spawnSync)('reg', ['delete', windowsRegistryKey(), '/v', windowsRegistryValueName(), '/f'], { stdio: 'ignore' });
|
|
216
|
+
return getWindowsStatus();
|
|
217
|
+
}
|
|
218
|
+
if (platform === 'linux') {
|
|
219
|
+
(0, node_child_process_1.spawnSync)('systemctl', ['--user', 'disable', '--now', linuxServiceName()], { stdio: 'ignore' });
|
|
220
|
+
(0, node_child_process_1.spawnSync)('systemctl', ['--user', 'daemon-reload'], { stdio: 'ignore' });
|
|
221
|
+
const servicePath = linuxServicePath();
|
|
222
|
+
if (node_fs_1.default.existsSync(servicePath)) {
|
|
223
|
+
node_fs_1.default.rmSync(servicePath, { force: true });
|
|
224
|
+
}
|
|
225
|
+
return getLinuxStatus();
|
|
226
|
+
}
|
|
227
|
+
throw new Error('cli_startup_unsupported');
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=startup.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forkit-connect",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"description": "Forkit Connect Local Engine - The Global AI Governance Fabric",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"assets",
|
|
13
14
|
"README.md",
|
|
14
15
|
"QUICKSTART.md"
|
|
15
16
|
],
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"better-sqlite3": "^12.10.0",
|
|
34
35
|
"cors": "^2.8.6",
|
|
35
36
|
"express": "^4.19.2",
|
|
37
|
+
"node-notifier": "^10.0.1",
|
|
36
38
|
"ps-list": "^8.1.1",
|
|
37
39
|
"uuid": "^10.0.0",
|
|
38
40
|
"ws": "^8.16.0",
|