omnikey-cli 1.0.12 → 1.0.13

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 CHANGED
@@ -8,6 +8,7 @@ OmnikeyAI is a productivity tool that helps you quickly rewrite selected text us
8
8
 
9
9
  - For more details about the app and its features, see the [main README](https://github.com/GurinderRawala/OmniKey-AI).
10
10
  - Download the latest macOS app here: [Download OmniKeyAI for macOS](https://omnikeyai-saas-fmytqc3dra-uc.a.run.app/macos/download)
11
+ - Download the latest Windows app here: [Download OmniKeyAI for Windows](https://omnikeyai-saas-fmytqc3dra-uc.a.run.app/windows/download)
11
12
 
12
13
  ## Features
13
14
 
@@ -7,6 +7,7 @@ const express_1 = __importDefault(require("express"));
7
7
  const cors_1 = __importDefault(require("cors"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const fs_1 = __importDefault(require("fs"));
10
+ const zlib_1 = __importDefault(require("zlib"));
10
11
  const subscriptionRoutes_1 = require("./subscriptionRoutes");
11
12
  const featureRoutes_1 = require("./featureRoutes");
12
13
  const db_1 = require("./db");
@@ -80,19 +81,30 @@ app.get('/macos/appcast', (req, res) => {
80
81
  // ── Windows distribution endpoints ───────────────────────────────────────────
81
82
  // These should match the values in windows/OmniKey.Windows.csproj
82
83
  // <Version> and windows/build_release_zip.ps1 $APP_VERSION.
83
- const WIN_VERSION = '1.0';
84
- const WIN_ZIP_FILENAME = 'OmniKeyAI-windows-x64.zip';
84
+ const WIN_VERSION = '1.1';
85
+ const WIN_ZIP_FILENAME = 'OmniKeyAI-windows-win-x64.zip';
85
86
  const WIN_ZIP_PATH = path_1.default.join(process.cwd(), 'windows', WIN_ZIP_FILENAME);
86
87
  // Serves the pre-built ZIP produced by windows/build_release_zip.ps1.
88
+ // Streams through gzip to reduce response size on Cloud Run.
87
89
  app.get('/windows/download', (_req, res) => {
88
- res.download(WIN_ZIP_PATH, WIN_ZIP_FILENAME, (err) => {
89
- if (err) {
90
- logger_1.logger.error('Failed to send Windows ZIP for download.', { error: err });
91
- if (!res.headersSent) {
92
- res.status(500).send('Unable to download file.');
93
- }
90
+ if (!fs_1.default.existsSync(WIN_ZIP_PATH)) {
91
+ res.status(404).send('File not found.');
92
+ return;
93
+ }
94
+ res.set({
95
+ 'Content-Type': 'application/zip',
96
+ 'Content-Disposition': `attachment; filename="${WIN_ZIP_FILENAME}"`,
97
+ 'Content-Encoding': 'gzip',
98
+ });
99
+ const fileStream = fs_1.default.createReadStream(WIN_ZIP_PATH);
100
+ const gzip = zlib_1.default.createGzip();
101
+ fileStream.on('error', (err) => {
102
+ logger_1.logger.error('Failed to send Windows ZIP for download.', { error: err });
103
+ if (!res.headersSent) {
104
+ res.status(500).send('Unable to download file.');
94
105
  }
95
106
  });
107
+ fileStream.pipe(gzip).pipe(res);
96
108
  });
97
109
  // JSON update-check endpoint consumed by UpdateChecker.cs on the Windows client.
98
110
  // Returns the latest version + download URL so the client can decide whether
@@ -82,12 +82,28 @@ function removeConfigAndDb() {
82
82
  killPersistenceAgent();
83
83
  // Remove SQLite database
84
84
  if (fs_1.default.existsSync(sqlitePath)) {
85
- try {
86
- fs_1.default.rmSync(sqlitePath);
87
- console.log(`Removed SQLite database: ${sqlitePath}`);
85
+ const maxAttempts = utils_1.isWindows ? 5 : 1;
86
+ let removed = false;
87
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
88
+ try {
89
+ fs_1.default.rmSync(sqlitePath);
90
+ console.log(`Removed SQLite database: ${sqlitePath}`);
91
+ removed = true;
92
+ break;
93
+ }
94
+ catch (e) {
95
+ if (utils_1.isWindows && attempt < maxAttempts && (e.code === 'EBUSY' || e.code === 'EPERM' || e.code === 'EACCES')) {
96
+ // File may still be locked by the daemon — wait ~1s and retry
97
+ (0, child_process_1.execSync)(`ping -n 2 127.0.0.1 > nul`, { stdio: 'pipe' });
98
+ }
99
+ else {
100
+ console.error(`Failed to remove SQLite database: ${e}`);
101
+ break;
102
+ }
103
+ }
88
104
  }
89
- catch (e) {
90
- console.error(`Failed to remove SQLite database: ${e}`);
105
+ if (!removed && utils_1.isWindows) {
106
+ console.error(`Failed to remove SQLite database after ${maxAttempts} attempts: ${sqlitePath}`);
91
107
  }
92
108
  }
93
109
  else {
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.12",
7
+ "version": "1.0.13",
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",
@@ -75,11 +75,26 @@ export function removeConfigAndDb() {
75
75
 
76
76
  // Remove SQLite database
77
77
  if (fs.existsSync(sqlitePath)) {
78
- try {
79
- fs.rmSync(sqlitePath);
80
- console.log(`Removed SQLite database: ${sqlitePath}`);
81
- } catch (e) {
82
- console.error(`Failed to remove SQLite database: ${e}`);
78
+ const maxAttempts = isWindows ? 5 : 1;
79
+ let removed = false;
80
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
81
+ try {
82
+ fs.rmSync(sqlitePath);
83
+ console.log(`Removed SQLite database: ${sqlitePath}`);
84
+ removed = true;
85
+ break;
86
+ } catch (e: any) {
87
+ if (isWindows && attempt < maxAttempts && (e.code === 'EBUSY' || e.code === 'EPERM' || e.code === 'EACCES')) {
88
+ // File may still be locked by the daemon — wait ~1s and retry
89
+ execSync(`ping -n 2 127.0.0.1 > nul`, { stdio: 'pipe' });
90
+ } else {
91
+ console.error(`Failed to remove SQLite database: ${e}`);
92
+ break;
93
+ }
94
+ }
95
+ }
96
+ if (!removed && isWindows) {
97
+ console.error(`Failed to remove SQLite database after ${maxAttempts} attempts: ${sqlitePath}`);
83
98
  }
84
99
  } else {
85
100
  console.log(`SQLite database does not exist: ${sqlitePath}`);