aegis-desktop 1.0.13 → 1.0.15

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 (96) hide show
  1. package/SOURCE-OFFER.txt +9 -0
  2. package/bin/aegis.js +1 -32
  3. package/lib/account-key.js +1 -56
  4. package/lib/auto.js +1 -430
  5. package/lib/avatar/companion.js +1 -698
  6. package/lib/avatar/cosmetics.js +1 -532
  7. package/lib/avatar/events.js +1 -344
  8. package/lib/avatar/holder-turn.js +1 -350
  9. package/lib/avatar/holders.js +1 -612
  10. package/lib/avatar/identity.js +1 -641
  11. package/lib/avatar/level.js +1 -368
  12. package/lib/avatar/mirror.js +1 -524
  13. package/lib/avatar/persona.js +1 -388
  14. package/lib/avatar/profile.js +1 -977
  15. package/lib/avatar/register.js +1 -307
  16. package/lib/avatar/store.js +1 -472
  17. package/lib/avatar/tiers.js +1 -38
  18. package/lib/avatar/transfer.js +1 -415
  19. package/lib/avatar/turn.js +1 -216
  20. package/lib/avatar/voice.js +1 -328
  21. package/lib/avatar/xp.js +1 -404
  22. package/lib/deep-link.js +1 -120
  23. package/lib/fingerprint.js +2 -347
  24. package/lib/google-connect.js +1 -169
  25. package/lib/local/agents.js +1 -105
  26. package/lib/local/autonomous.js +1 -1045
  27. package/lib/local/claude-pro.js +1 -993
  28. package/lib/local/context.js +1 -95
  29. package/lib/local/engine.js +1 -3228
  30. package/lib/local/entitlement.js +1 -654
  31. package/lib/local/git-scope.js +1 -228
  32. package/lib/local/local.js +1 -2135
  33. package/lib/local/prompt.js +1 -275
  34. package/lib/local/queue.js +1 -560
  35. package/lib/local/session-rounds.js +1 -208
  36. package/lib/local/shell.js +1 -680
  37. package/lib/local/telemetry.js +1 -470
  38. package/lib/local/tools.js +1 -1238
  39. package/lib/local/turn-guard.js +1 -300
  40. package/lib/local/worktree-lock.js +1 -235
  41. package/lib/provider-key-mirror.js +1 -252
  42. package/lib/quick-launcher.js +1 -84
  43. package/lib/settings.js +1 -890
  44. package/lib/sync/memory-queue.js +1 -60
  45. package/lib/sync/persist-gate.js +1 -148
  46. package/lib/sync/sessions.js +1 -106
  47. package/lib/window-state.js +1 -66
  48. package/main.js +3 -4390
  49. package/package.json +3 -5
  50. package/preload.js +3 -628
  51. package/renderer/app.js +1 -6560
  52. package/renderer/avatar/assemble.js +1 -335
  53. package/renderer/avatar/avatar.js +1 -380
  54. package/renderer/avatar/cards.js +1 -141
  55. package/renderer/avatar/hud.js +1 -206
  56. package/renderer/avatar/machine.js +1 -213
  57. package/renderer/avatar/pane.js +1 -439
  58. package/renderer/avatar/parts.js +1 -437
  59. package/renderer/budget.js +1 -168
  60. package/renderer/companion.js +1 -223
  61. package/renderer/diff.js +1 -359
  62. package/renderer/diffview.js +1 -336
  63. package/renderer/fingerprint.js +3 -720
  64. package/renderer/markdown.js +1 -168
  65. package/renderer/provider-toolbar.js +1 -134
  66. package/renderer/providers.js +1 -259
  67. package/renderer/quick.js +1 -191
  68. package/renderer/stream-policy.js +1 -306
  69. package/renderer/transcript-view.js +1 -323
  70. package/renderer/usage.js +1 -1239
  71. package/vendor/aegis.js +1 -2054
  72. package/vendor/attest.js +1 -442
  73. package/vendor/authorship-key.js +1 -410
  74. package/vendor/auto-provision.js +1 -134
  75. package/vendor/brain-catalog.js +1 -268
  76. package/vendor/byok-catalog.js +1 -230
  77. package/vendor/credentials.js +1 -494
  78. package/vendor/device-fingerprint.js +1 -141
  79. package/vendor/drive-connect.js +1 -85
  80. package/vendor/drive-upload.js +1 -174
  81. package/vendor/env-file.js +1 -1273
  82. package/vendor/fingerprint.js +1 -1064
  83. package/vendor/foreign-memory.js +1 -669
  84. package/vendor/google-signin.js +1 -125
  85. package/vendor/hooks.js +1 -430
  86. package/vendor/model-discovery.js +1 -330
  87. package/vendor/platform.js +1 -937
  88. package/vendor/prefs.js +1 -351
  89. package/vendor/presence-constants.js +1 -107
  90. package/vendor/presence.js +1 -438
  91. package/vendor/record-vault.js +3 -1055
  92. package/vendor/session-store.js +1 -548
  93. package/vendor/topup.js +1 -297
  94. package/vendor/touch.js +1 -458
  95. package/vendor/update.js +1 -704
  96. package/vendor/user-models.js +1 -381
@@ -1,254 +1,3 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  // Copyright (C) 2026 Niklas Borneklint — AEGIS Code (aegiscode) / Aegiscloud.
3
- // AEGIS Code (aegiscode) — source: https://github.com/aegisinfo/aegiscode-plugin
4
- // Conveying a modified copy, or running one as a network service, owes the
5
- // corresponding source under this licence (§5/§13) — see LICENSING.md.
6
- 'use strict';
7
-
8
- /**
9
- * provider-key-mirror.js — make a provider key saved in the DESKTOP visible to
10
- * every other host on the same machine.
11
- *
12
- * The desktop's Provider settings rows persist into its own encrypted settings
13
- * store (`desktop/lib/settings.js` -> `settings.json` under the app's userData
14
- * dir). That store is private to this app: `aegiscode` (the CLI) and the MCP
15
- * plugin never read it, and they cannot — it is an encrypted Electron store in
16
- * another process's data directory. So a key added in the desktop was invisible
17
- * to the CLI on the next run: same machine, same provider, key asked for twice.
18
- *
19
- * The fix is not to teach every host to open an encrypted Electron store. It is
20
- * to write the key where all four hosts already look at start-up —
21
- * `~/.aegiscode/.env`, through the ONE shared writer (`client/env-file.js`
22
- * `setEnvValue`). After this, "add your provider key in the app" and "put it in
23
- * ~/.aegiscode/.env" are the same instruction, which is the point.
24
- *
25
- * Policy, deliberately narrow:
26
- *
27
- * - PROVIDER keys only. The AEGIS *account* key is already shared through
28
- * `credentials.json` (`client/credentials.js`), which the CLI, the MCP
29
- * plugin and the desktop all read. A second copy in the env file would be a
30
- * second authority that can silently disagree with the first — exactly the
31
- * "which one won?" failure env-file.js refuses for duplicate lines. So
32
- * `setAegisKey()` is deliberately NOT wrapped.
33
- * - The variable name comes from `envFile.envVarFor(provider)`, the same
34
- * mapping the CLI's model picker uses (`keyForModelId`), and must end in
35
- * `_API_KEY`. A name we cannot map is a name we do not invent: an
36
- * unrecognised provider leaves the file untouched rather than growing an
37
- * unrelated variable.
38
- * - Removing a key only touches the file if the file actually carries that
39
- * variable, so "Remove" on a provider the file never knew about does not
40
- * add a stray `OPENAI_API_KEY=` line to a hand-written file.
41
- * - A failure to mirror is REPORTED and swallowed. The key IS saved (the
42
- * encrypted store has it); only the cross-host copy failed, and refusing
43
- * the whole save over that would throw away the key the user just typed.
44
- */
45
-
46
- /** Reserved namespaces (`__aegis`, `__quickLauncher`, …) are the store's own
47
- * bookkeeping, not providers — never a key variable. */
48
- const RESERVED_PREFIX = '__';
49
-
50
- /** Every provider key variable in this product family ends this way. */
51
- const KEY_VAR_SUFFIX = /_API_KEY$/;
52
-
53
- /**
54
- * Write one provider key into the shared env file.
55
- *
56
- * @param {object} envFile client/env-file.js (injected: this module must stay
57
- * unit-testable without touching the real home dir)
58
- * @param {string} provider provider id, e.g. 'openai'
59
- * @param {string} key the key; '' means "clear it"
60
- * @param {object} [opts] `onWarn(message)`, `envOpts` forwarded to env-file
61
- * (its `{ file, env }` seam, used by tests)
62
- * @returns {object|null} env-file's own result, or null when nothing was
63
- * mirrored (no mapping, reserved row, absent variable)
64
- */
65
- function mirrorProviderKeyToEnvFile(envFile, provider, key, opts = {}) {
66
- const warn = typeof opts.onWarn === 'function' ? opts.onWarn : () => {};
67
- const envOpts = opts.envOpts || {};
68
- if (!envFile || typeof envFile.setEnvValue !== 'function') return null;
69
- if (typeof provider !== 'string' || !provider) return null;
70
- if (provider.startsWith(RESERVED_PREFIX)) return null;
71
-
72
- const name = typeof envFile.envVarFor === 'function' ? envFile.envVarFor(provider) : '';
73
- if (!name || !KEY_VAR_SUFFIX.test(name)) return null;
74
-
75
- try {
76
- if (key) return envFile.setEnvValue(name, key, envOpts);
77
- const status =
78
- typeof envFile.keyStatus === 'function' ? envFile.keyStatus(name, envOpts) : null;
79
- if (!status || !status.inFile) return null;
80
- if (typeof envFile.clearEnvValue === 'function') {
81
- return envFile.clearEnvValue(name, envOpts);
82
- }
83
- // An older vendored env-file without a remover. Writing an empty value is
84
- // NOT a removal — `setEnvValue` refuses an empty value outright, so that
85
- // call returned an error and left the stale line in place. Unset the live
86
- // variable and say plainly that the file still carries it.
87
- if (envOpts.env) delete envOpts.env[name];
88
- else delete process.env[name];
89
- warn(
90
- `removed ${provider}'s key in the app, but ${name} is still in the shared env file — `
91
- + 'this build has no clearEnvValue; delete the line by hand',
92
- );
93
- return null;
94
- } catch (e) {
95
- warn(`could not mirror ${provider}'s key into the shared env file: ${e && e.message}`);
96
- return null;
97
- }
98
- }
99
-
100
- /**
101
- * Copy every provider key the store already holds into the shared env file.
102
- *
103
- * `wrapProviderKeyMirror` above is a WRITE-TIME hook: it mirrors a key at the
104
- * moment it is saved. That leaves a real gap the hook cannot close, because a
105
- * key saved before the hook existed never fires it — an install whose provider
106
- * row predates this module (or any row written while the wrapper was not
107
- * installed, e.g. a direct settings write from a test or a repair script) keeps
108
- * its key in the encrypted store alone, and the CLI never sees it. A stored key
109
- * is not a mirrored key; only a fresh Save used to make them the same thing.
110
- *
111
- * The same gap swallows a "blank = keep" save: `renderer/app.js` saves a
112
- * provider row with `key` undefined when the key field is left empty (that
113
- * means "keep the stored one" — see the wrapper's comment), so the wrapper
114
- * correctly mirrors nothing and the row's real key stays host-local for ever.
115
- *
116
- * So this runs ONCE at start-up and reconciles the two stores by reading, not
117
- * by writing: for every non-reserved row that HAS a stored key whose variable
118
- * the shared file does not already carry, write it. It is:
119
- *
120
- * - idempotent — a second call on an already-synced machine mirrors nothing
121
- * (the `keyStatus(...).inFile` check is the guard), and it never rewrites a
122
- * variable that is already present, so a hand-edited `.env` keeps its own
123
- * spelling, comments and line order;
124
- * - one-directional — store -> file only. The file is never read back into
125
- * the encrypted store, so this cannot become a merge loop or overwrite a
126
- * newer key the CLI wrote (which the desktop would then be second-guessing);
127
- * - non-fatal — a row that cannot be decrypted or written is REPORTED and
128
- * skipped. A start-up reconcile must never keep the window from opening.
129
- *
130
- * Must run after app 'ready': `safeStorage` (which decrypts the stored key) is
131
- * not usable before then.
132
- *
133
- * @param {object} store a settings store (needs `list`, and `rawKey` for the
134
- * decrypted value — the exact pair settings.js exposes)
135
- * @param {object} envFile client/env-file.js
136
- * @param {object} [opts] `onWarn`, `envOpts` (see above)
137
- * @returns {{mirrored:string[], skipped:string[], failed:string[]}} what
138
- * happened per provider, so a caller/test can assert rather than guess
139
- */
140
- function backfillProviderKeys(store, envFile, opts = {}) {
141
- const warn = typeof opts.onWarn === 'function' ? opts.onWarn : () => {};
142
- const envOpts = opts.envOpts || {};
143
- const out = { mirrored: [], skipped: [], failed: [] };
144
- if (!store || typeof store.list !== 'function') return out;
145
- if (!envFile || typeof envFile.envVarFor !== 'function') return out;
146
-
147
- let rows = [];
148
- try {
149
- rows = store.list() || [];
150
- } catch (e) {
151
- warn(`could not read the provider store to backfill the shared env file: ${e && e.message}`);
152
- return out;
153
- }
154
-
155
- for (const row of rows) {
156
- const provider = row && row.provider;
157
- // Same filters as the write-time mirror: a reserved row is the store's own
158
- // bookkeeping, and an unmappable name is a name we do not invent.
159
- if (typeof provider !== 'string' || !provider) continue;
160
- if (provider.startsWith(RESERVED_PREFIX)) continue;
161
-
162
- const name = envFile.envVarFor(provider);
163
- if (!name || !KEY_VAR_SUFFIX.test(name)) {
164
- out.skipped.push(provider);
165
- continue;
166
- }
167
- // A name the env file itself refuses (a production secret, not a host key)
168
- // is not a failure to report — `setEnvValue` would reject it by design.
169
- if (typeof envFile.isForeignSecret === 'function' && envFile.isForeignSecret(name)) {
170
- out.skipped.push(provider);
171
- continue;
172
- }
173
-
174
- // Already shared? Then there is nothing to do, and — importantly — nothing
175
- // to overwrite. This is the idempotence guard.
176
- let status = null;
177
- try {
178
- status = typeof envFile.keyStatus === 'function' ? envFile.keyStatus(name, envOpts) : null;
179
- } catch { /* unreadable file is "not in the file"; the write below reports it */ }
180
- if (status && status.inFile) {
181
- out.skipped.push(provider);
182
- continue;
183
- }
184
-
185
- // `row.configured` is the store's own "a key is stored" flag (settings.js
186
- // get() derives it from the decrypted value), so a base-URL-only row is
187
- // skipped here rather than being asked for a key it never had.
188
- if (row.configured === false) {
189
- out.skipped.push(provider);
190
- continue;
191
- }
192
-
193
- let key = '';
194
- try {
195
- key = typeof store.rawKey === 'function' ? store.rawKey(provider) : '';
196
- } catch (e) {
197
- warn(`could not decrypt ${provider}'s stored key for the shared env file: ${e && e.message}`);
198
- out.failed.push(provider);
199
- continue;
200
- }
201
- if (!key) {
202
- out.skipped.push(provider);
203
- continue;
204
- }
205
-
206
- const res = mirrorProviderKeyToEnvFile(envFile, provider, key, opts);
207
- if (res && res.ok) out.mirrored.push(provider);
208
- else out.failed.push(provider);
209
- }
210
- return out;
211
- }
212
-
213
- /**
214
- * Wrap a provider-settings store so every key saved or removed through it is
215
- * also written to the shared env file.
216
- *
217
- * Wrapping the store (rather than each caller) is the whole point: the Settings
218
- * pane, the welcome flow's provider rows and any future caller all funnel
219
- * through `store.set` / `store.remove`, so there is exactly one place that can
220
- * forget to mirror — and this is it.
221
- *
222
- * @param {object} store a settings store (settings.get/set/remove/list)
223
- * @param {object} envFile client/env-file.js
224
- * @param {object} [opts] `onWarn`, `envOpts` (see above)
225
- * @returns {object} the same store, wrapped
226
- */
227
- function wrapProviderKeyMirror(store, envFile, opts = {}) {
228
- if (!store || typeof store.set !== 'function') return store;
229
- const mirror = (provider, key) => mirrorProviderKeyToEnvFile(envFile, provider, key, opts);
230
-
231
- const rawSet = store.set.bind(store);
232
- const rawRemove = typeof store.remove === 'function' ? store.remove.bind(store) : null;
233
-
234
- store.set = (provider, cfg) => {
235
- const res = rawSet(provider, cfg);
236
- // A row with no key is a base-URL/local-daemon row: there is no secret to
237
- // share, and mirroring would write an empty variable into a file every host
238
- // sources. `cfg.key` undefined OR empty both mean "no key supplied"
239
- // (a blank field in the pane means "keep the stored one").
240
- if (cfg && typeof cfg.key === 'string' && cfg.key) mirror(provider, cfg.key);
241
- return res;
242
- };
243
-
244
- if (rawRemove) {
245
- store.remove = (provider) => {
246
- const res = rawRemove(provider);
247
- mirror(provider, '');
248
- return res;
249
- };
250
- }
251
- return store;
252
- }
253
-
254
- module.exports = { mirrorProviderKeyToEnvFile, wrapProviderKeyMirror, backfillProviderKeys };
3
+ "use strict";const RESERVED_PREFIX="__",KEY_VAR_SUFFIX=/_API_KEY$/;function mirrorProviderKeyToEnvFile(e,r,n,t={}){const o="function"==typeof t.onWarn?t.onWarn:()=>{},i=t.envOpts||{};if(!e||"function"!=typeof e.setEnvValue)return null;if("string"!=typeof r||!r)return null;if(r.startsWith(RESERVED_PREFIX))return null;const s="function"==typeof e.envVarFor?e.envVarFor(r):"";if(!s||!KEY_VAR_SUFFIX.test(s))return null;try{if(n)return e.setEnvValue(s,n,i);const t="function"==typeof e.keyStatus?e.keyStatus(s,i):null;return t&&t.inFile?"function"==typeof e.clearEnvValue?e.clearEnvValue(s,i):(i.env?delete i.env[s]:delete process.env[s],o(`removed ${r}'s key in the app, but ${s} is still in the shared env file — this build has no clearEnvValue; delete the line by hand`),null):null}catch(e){return o(`could not mirror ${r}'s key into the shared env file: ${e&&e.message}`),null}}function backfillProviderKeys(e,r,n={}){const t="function"==typeof n.onWarn?n.onWarn:()=>{},o=n.envOpts||{},i={mirrored:[],skipped:[],failed:[]};if(!e||"function"!=typeof e.list)return i;if(!r||"function"!=typeof r.envVarFor)return i;let s=[];try{s=e.list()||[]}catch(e){return t(`could not read the provider store to backfill the shared env file: ${e&&e.message}`),i}for(const u of s){const s=u&&u.provider;if("string"!=typeof s||!s)continue;if(s.startsWith(RESERVED_PREFIX))continue;const l=r.envVarFor(s);if(!l||!KEY_VAR_SUFFIX.test(l)){i.skipped.push(s);continue}if("function"==typeof r.isForeignSecret&&r.isForeignSecret(l)){i.skipped.push(s);continue}let f=null;try{f="function"==typeof r.keyStatus?r.keyStatus(l,o):null}catch{}if(f&&f.inFile){i.skipped.push(s);continue}if(!1===u.configured){i.skipped.push(s);continue}let c="";try{c="function"==typeof e.rawKey?e.rawKey(s):""}catch(e){t(`could not decrypt ${s}'s stored key for the shared env file: ${e&&e.message}`),i.failed.push(s);continue}if(!c){i.skipped.push(s);continue}const a=mirrorProviderKeyToEnvFile(r,s,c,n);a&&a.ok?i.mirrored.push(s):i.failed.push(s)}return i}function wrapProviderKeyMirror(e,r,n={}){if(!e||"function"!=typeof e.set)return e;const t=(e,t)=>mirrorProviderKeyToEnvFile(r,e,t,n),o=e.set.bind(e),i="function"==typeof e.remove?e.remove.bind(e):null;return e.set=(e,r)=>{const n=o(e,r);return r&&"string"==typeof r.key&&r.key&&t(e,r.key),n},i&&(e.remove=e=>{const r=i(e);return t(e,""),r}),e}module.exports={mirrorProviderKeyToEnvFile:mirrorProviderKeyToEnvFile,wrapProviderKeyMirror:wrapProviderKeyMirror,backfillProviderKeys:backfillProviderKeys};
@@ -1,86 +1,3 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  // Copyright (C) 2026 Niklas Borneklint — AEGIS Code (aegiscode) / Aegiscloud.
3
- // AEGIS Code (aegiscode) — source: https://github.com/aegisinfo/aegiscode-plugin
4
- // Conveying a modified copy, or running one as a network service, owes the
5
- // corresponding source under this licence (§5/§13) — see LICENSING.md.
6
- 'use strict';
7
-
8
- /**
9
- * quick-launcher.js — pure geometry + gating logic for the global quick-
10
- * launcher popup (native desktop plumbing). Mirrors desktop/lib/window-state.js:
11
- * no Electron import, so both functions unit-test without the Electron binary.
12
- * main.js wires the result into a BrowserWindow + globalShortcut; this module
13
- * only decides where the window should sit and whether the shortcut should be
14
- * registered at all.
15
- */
16
-
17
- /**
18
- * A global shortcut is a machine-wide hook — every packaged build ships it,
19
- * but a `npm start` dev run must NOT silently start grabbing a hotkey that
20
- * might collide with whatever else the developer has running, unless they've
21
- * explicitly opted in via the settings flag.
22
- */
23
- function shouldEnableGlobalShortcut({ isPackaged, enabled } = {}) {
24
- return Boolean(isPackaged) || Boolean(enabled);
25
- }
26
-
27
- /**
28
- * Where the launcher window should land: centred on the cursor's current
29
- * position, clamped so the whole window stays within that cursor's display
30
- * work area (never straddling into an unplugged second monitor, never
31
- * hanging off a screen edge). Falls back to centring on the first available
32
- * display — or the given fallback rectangle — when there is no usable cursor
33
- * point or display list (e.g. a headless test).
34
- *
35
- * `cursor` / `displays` take the plain shapes electron.screen already
36
- * returns (`{x,y}` / `{workArea:{x,y,width,height}}`), so this stays pure and
37
- * Electron-free for testing, exactly like window-state.js's clampToDisplay.
38
- */
39
- function computeQuickLauncherBounds({ cursor, displays, size, fallback } = {}) {
40
- const width = Math.max(1, (size && size.width) || 560);
41
- const height = Math.max(1, (size && size.height) || 320);
42
- const list = Array.isArray(displays) ? displays : [];
43
- const point =
44
- cursor && Number.isFinite(cursor.x) && Number.isFinite(cursor.y) ? cursor : null;
45
-
46
- const containing = point
47
- ? list.find((d) => {
48
- const wa = d && d.workArea;
49
- return (
50
- wa &&
51
- point.x >= wa.x &&
52
- point.x < wa.x + wa.width &&
53
- point.y >= wa.y &&
54
- point.y < wa.y + wa.height
55
- );
56
- })
57
- : null;
58
-
59
- const target = containing || list[0] || null;
60
- if (!target || !target.workArea) {
61
- return {
62
- x: (fallback && fallback.x) || 0,
63
- y: (fallback && fallback.y) || 0,
64
- width,
65
- height,
66
- };
67
- }
68
-
69
- const wa = target.workArea;
70
- let x;
71
- let y;
72
- if (point) {
73
- x = Math.round(point.x - width / 2);
74
- y = Math.round(point.y - height / 2);
75
- } else {
76
- x = Math.round(wa.x + (wa.width - width) / 2);
77
- y = Math.round(wa.y + (wa.height - height) / 2);
78
- }
79
-
80
- x = Math.min(Math.max(x, wa.x), Math.max(wa.x, wa.x + wa.width - width));
81
- y = Math.min(Math.max(y, wa.y), Math.max(wa.y, wa.y + wa.height - height));
82
-
83
- return { x, y, width, height };
84
- }
85
-
86
- module.exports = { shouldEnableGlobalShortcut, computeQuickLauncherBounds };
3
+ "use strict";function shouldEnableGlobalShortcut({isPackaged:t,enabled:a}={}){return Boolean(t)||Boolean(a)}function computeQuickLauncherBounds({cursor:t,displays:a,size:h,fallback:e}={}){const u=Math.max(1,h&&h.width||560),n=Math.max(1,h&&h.height||320),o=Array.isArray(a)?a:[],r=t&&Number.isFinite(t.x)&&Number.isFinite(t.y)?t:null,i=r?o.find((t=>{const a=t&&t.workArea;return a&&r.x>=a.x&&r.x<a.x+a.width&&r.y>=a.y&&r.y<a.y+a.height})):null,l=i||o[0]||null;if(!l||!l.workArea)return{x:e&&e.x||0,y:e&&e.y||0,width:u,height:n};const c=l.workArea;let d,s;return r?(d=Math.round(r.x-u/2),s=Math.round(r.y-n/2)):(d=Math.round(c.x+(c.width-u)/2),s=Math.round(c.y+(c.height-n)/2)),d=Math.min(Math.max(d,c.x),Math.max(c.x,c.x+c.width-u)),s=Math.min(Math.max(s,c.y),Math.max(c.y,c.y+c.height-n)),{x:d,y:s,width:u,height:n}}module.exports={shouldEnableGlobalShortcut:shouldEnableGlobalShortcut,computeQuickLauncherBounds:computeQuickLauncherBounds};