pushary 1.9.52 → 1.9.54
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/CHANGELOG.md +11 -1
- package/dist/bin/pushary-clean.js +89 -255
- package/dist/bin/pushary-codex-session.js +3 -3
- package/dist/bin/pushary-setup.js +2 -2
- package/dist/{chunk-36NGFHE4.js → chunk-E46NE7FB.js} +2 -0
- package/dist/{chunk-DMJFW4KL.js → chunk-T5L5NWT3.js} +6 -3
- package/dist/chunk-ZWOWEXCV.js +525 -0
- package/dist/{codex-app-cards-switch-OUQ3DUWF.js → codex-app-cards-switch-P4RVJNRV.js} +15 -3
- package/dist/{codex-desktop-launch-EIFLPLB7.js → codex-desktop-launch-RIBIFXSF.js} +6 -2
- package/package.json +1 -1
- package/dist/chunk-OHSHDQZF.js +0 -271
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CODEX_APP_CARDS_DIRECTORY,
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
LSREGISTER,
|
|
5
|
+
MAC_APP_BUNDLE_ID,
|
|
6
|
+
MAC_DEFAULTS_DOMAINS,
|
|
7
|
+
MAC_KEYCHAIN_ACCOUNTS,
|
|
8
|
+
codexAppCardsFolderStaysOnThisMac,
|
|
9
|
+
developerDefaults,
|
|
10
|
+
installedPusharyBundles,
|
|
11
|
+
liveMacStatePresence,
|
|
12
|
+
registeredPusharyBundles,
|
|
13
|
+
removeCodexAppCardsFromThisMac,
|
|
14
|
+
runningMacAppPIDs,
|
|
15
|
+
storedMacAppState,
|
|
16
|
+
storedPusharyKeychainServices,
|
|
17
|
+
waitForMacAppExit
|
|
18
|
+
} from "../chunk-ZWOWEXCV.js";
|
|
6
19
|
import {
|
|
7
20
|
PUSHARY_SKILL_NAME,
|
|
8
21
|
PUSHARY_SKILL_SOURCE,
|
|
9
22
|
createGuards
|
|
10
23
|
} from "../chunk-EUW7JL2K.js";
|
|
11
|
-
import "../chunk-
|
|
24
|
+
import "../chunk-T5L5NWT3.js";
|
|
12
25
|
import "../chunk-XCEN33UP.js";
|
|
13
26
|
import {
|
|
14
27
|
describeCliKeyRevocation,
|
|
@@ -108,7 +121,7 @@ import {
|
|
|
108
121
|
removeClaudeAlias,
|
|
109
122
|
shellProfileCandidates
|
|
110
123
|
} from "../chunk-VYBH6D4X.js";
|
|
111
|
-
import "../chunk-
|
|
124
|
+
import "../chunk-E46NE7FB.js";
|
|
112
125
|
import "../chunk-U2L42GVI.js";
|
|
113
126
|
import "../chunk-3RPN7AAT.js";
|
|
114
127
|
import "../chunk-JBT3ZSJS.js";
|
|
@@ -185,194 +198,14 @@ import {
|
|
|
185
198
|
} from "../chunk-LF3TLC7B.js";
|
|
186
199
|
|
|
187
200
|
// bin/pushary-clean.ts
|
|
188
|
-
import { existsSync as
|
|
189
|
-
import { dirname, join as
|
|
190
|
-
import { homedir as
|
|
201
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync4 } from "fs";
|
|
202
|
+
import { dirname, join as join5 } from "path";
|
|
203
|
+
import { homedir as homedir4, tmpdir } from "os";
|
|
191
204
|
import { confirm } from "@inquirer/prompts";
|
|
192
205
|
import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
|
|
193
206
|
|
|
194
|
-
// src/cli/mac-leftovers.ts
|
|
195
|
-
import { execSync, execFileSync } from "child_process";
|
|
196
|
-
import { existsSync, readdirSync } from "fs";
|
|
197
|
-
import { homedir } from "os";
|
|
198
|
-
import { isAbsolute, join } from "path";
|
|
199
|
-
var MAC_APP_BUNDLE = "/Applications/Pushary.app";
|
|
200
|
-
var MAC_APP_BUNDLE_ID = "com.pushary.app";
|
|
201
|
-
var installedPusharyBundles = (home = homedir()) => [MAC_APP_BUNDLE, join(home, "Applications", "Pushary.app")];
|
|
202
|
-
var LSREGISTER = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
|
|
203
|
-
var TEST_DEFAULTS_PREFIXES = [
|
|
204
|
-
"com.pushary.mac.tests.",
|
|
205
|
-
"com.pushary.tests.",
|
|
206
|
-
"pushary.tests.",
|
|
207
|
-
"pushary.quiet-mode-test.",
|
|
208
|
-
"pushary.drafts.test.",
|
|
209
|
-
"pushary-optin-",
|
|
210
|
-
"pushary-completion-test-",
|
|
211
|
-
"pushary-updates-only-"
|
|
212
|
-
];
|
|
213
|
-
var UUID = "[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}";
|
|
214
|
-
var UNPREFIXED_TEST_DEFAULTS_DOMAIN = new RegExp(`^(?:owner-mode|fx-model)-${UUID}$`);
|
|
215
|
-
var DEVELOPER_BUILD_DEFAULTS_DOMAIN = "PusharyMac";
|
|
216
|
-
var isDeveloperDefaultsDomain = (domain) => domain === DEVELOPER_BUILD_DEFAULTS_DOMAIN || UNPREFIXED_TEST_DEFAULTS_DOMAIN.test(domain) || TEST_DEFAULTS_PREFIXES.some((prefix) => domain.startsWith(prefix));
|
|
217
|
-
var PREFERENCES_FILE_EXTENSION = ".plist";
|
|
218
|
-
var preferencesDirectory = (home) => join(home, "Library", "Preferences");
|
|
219
|
-
var preferencesFile = (home, domain) => join(preferencesDirectory(home), `${domain}${PREFERENCES_FILE_EXTENSION}`);
|
|
220
|
-
var namesIn = (directory) => {
|
|
221
|
-
try {
|
|
222
|
-
return readdirSync(directory);
|
|
223
|
-
} catch {
|
|
224
|
-
return [];
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
var developerDefaults = (home = homedir()) => namesIn(preferencesDirectory(home)).filter((name) => name.endsWith(PREFERENCES_FILE_EXTENSION)).map((name) => name.slice(0, -PREFERENCES_FILE_EXTENSION.length)).filter(isDeveloperDefaultsDomain).map((domain) => ({ domain, file: preferencesFile(home, domain) }));
|
|
228
|
-
var BUNDLE_NAME = "Pushary.app";
|
|
229
|
-
var DUMP_RECORD_SEPARATOR = /^-{20,}$/m;
|
|
230
|
-
var DUMP_PATH_LINES = /^[ \t]*path:[ \t]+(.+?)(?: \(0x[0-9a-f]+\))?[ \t]*$/gm;
|
|
231
|
-
var DUMP_IDENTIFIER_LINES = /^[ \t]*identifier:[ \t]+(\S+)/gm;
|
|
232
|
-
var capturedIn = (text, lines) => [...text.matchAll(lines)].flatMap((match) => match[1] === void 0 ? [] : [match[1]]);
|
|
233
|
-
var appCopyNamedByRecord = (record) => {
|
|
234
|
-
const paths = capturedIn(record, DUMP_PATH_LINES);
|
|
235
|
-
const identifiers = capturedIn(record, DUMP_IDENTIFIER_LINES);
|
|
236
|
-
const namesOneAppCopy = paths.length === 1 && identifiers.length === 1 && identifiers[0] === MAC_APP_BUNDLE_ID;
|
|
237
|
-
return namesOneAppCopy ? paths : [];
|
|
238
|
-
};
|
|
239
|
-
var isAtOrInside = (path, bundle) => path === bundle || path.startsWith(`${bundle}/`);
|
|
240
|
-
var isUnderBundleNamedPushary = (path) => path.split("/").includes(BUNDLE_NAME);
|
|
241
|
-
var bundlesInLaunchServicesDump = (dump) => {
|
|
242
|
-
const appCopies = dump.split(DUMP_RECORD_SEPARATOR).flatMap(appCopyNamedByRecord);
|
|
243
|
-
const isOurs = (path) => isUnderBundleNamedPushary(path) || appCopies.some((copy) => isAtOrInside(path, copy));
|
|
244
|
-
return [...new Set(capturedIn(dump, DUMP_PATH_LINES).filter(isOurs))];
|
|
245
|
-
};
|
|
246
|
-
var outsideInstalledBundles = (registered, installed) => registered.filter((path) => !installed.some((bundle) => isAtOrInside(path, bundle)));
|
|
247
|
-
var registeredPusharyBundles = (installed = installedPusharyBundles()) => {
|
|
248
|
-
if (!existsSync(LSREGISTER)) return [];
|
|
249
|
-
try {
|
|
250
|
-
const dump = execSync(`${LSREGISTER} -dump`, {
|
|
251
|
-
encoding: "utf-8",
|
|
252
|
-
timeout: 6e4,
|
|
253
|
-
maxBuffer: 256 * 1024 * 1024
|
|
254
|
-
});
|
|
255
|
-
return outsideInstalledBundles(bundlesInLaunchServicesDump(dump), installed);
|
|
256
|
-
} catch {
|
|
257
|
-
return [];
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
var MAC_KEYCHAIN_SERVICE = "com.pushary.app.mac";
|
|
261
|
-
var MAC_KEYCHAIN_ACCOUNTS = [
|
|
262
|
-
"pushary.site-api-key",
|
|
263
|
-
"pushary.site-id",
|
|
264
|
-
"pushary.partner-enrollments",
|
|
265
|
-
"pushary.partner-device-key",
|
|
266
|
-
"clerk.device-token",
|
|
267
|
-
"clerk.session-id",
|
|
268
|
-
"clerkDeviceToken",
|
|
269
|
-
"cachedClient",
|
|
270
|
-
"cachedClientServerDate",
|
|
271
|
-
"cachedEnvironment"
|
|
272
|
-
];
|
|
273
|
-
var MAC_DEFAULTS_DOMAINS = ["com.pushary.app", "pushary-bridge", "pushary.render"];
|
|
274
|
-
var PRESENCE_PROBE_TIMEOUT_MS = 1e4;
|
|
275
|
-
var commandSucceeds = (file, args) => {
|
|
276
|
-
try {
|
|
277
|
-
execFileSync(file, args, { stdio: "ignore", timeout: PRESENCE_PROBE_TIMEOUT_MS });
|
|
278
|
-
return true;
|
|
279
|
-
} catch {
|
|
280
|
-
return false;
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
var KEYCHAIN_ITEM_NOT_FOUND = 44;
|
|
284
|
-
var keychainItemMayExist = (service, account) => {
|
|
285
|
-
try {
|
|
286
|
-
execFileSync("security", ["find-generic-password", "-s", service, "-a", account], { stdio: "ignore" });
|
|
287
|
-
return true;
|
|
288
|
-
} catch (error) {
|
|
289
|
-
return !(error instanceof Error && "status" in error && error.status === KEYCHAIN_ITEM_NOT_FOUND);
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
var liveMacStatePresence = {
|
|
293
|
-
keychainItem: keychainItemMayExist,
|
|
294
|
-
defaultsDomain: (domain) => commandSucceeds("defaults", ["read", domain])
|
|
295
|
-
};
|
|
296
|
-
var macLibraryState = (home = homedir()) => [
|
|
297
|
-
join(home, "Library", "Application Support", "Pushary"),
|
|
298
|
-
join(home, "Library", "Caches", "com.pushary.app"),
|
|
299
|
-
join(home, "Library", "Caches", "com.pushary.app.sparkle"),
|
|
300
|
-
join(home, "Library", "Saved Application State", "com.pushary.app.savedState"),
|
|
301
|
-
join(home, "Library", "Caches", "pushary-bridge"),
|
|
302
|
-
join(home, "Library", "HTTPStorages", "com.pushary.app"),
|
|
303
|
-
join(home, "Library", "HTTPStorages", "com.pushary.app.binarycookies"),
|
|
304
|
-
join(home, "Library", "HTTPStorages", "pushary-bridge"),
|
|
305
|
-
...MAC_DEFAULTS_DOMAINS.map((domain) => preferencesFile(home, domain))
|
|
306
|
-
];
|
|
307
|
-
var USER_CACHE_ENTRIES = [MAC_APP_BUNDLE_ID, "pushary-bridge", "PusharyBridge"];
|
|
308
|
-
var macUserCacheState = (reportedUserCacheDirectory) => {
|
|
309
|
-
const directory = reportedUserCacheDirectory.trim();
|
|
310
|
-
return isAbsolute(directory) ? USER_CACHE_ENTRIES.map((entry) => join(directory, entry)) : [];
|
|
311
|
-
};
|
|
312
|
-
var UNKNOWN_USER_CACHE_DIRECTORY = "";
|
|
313
|
-
var reportedDarwinUserCacheDirectory = () => {
|
|
314
|
-
try {
|
|
315
|
-
return execFileSync("getconf", ["DARWIN_USER_CACHE_DIR"], {
|
|
316
|
-
encoding: "utf-8",
|
|
317
|
-
timeout: PRESENCE_PROBE_TIMEOUT_MS,
|
|
318
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
319
|
-
});
|
|
320
|
-
} catch {
|
|
321
|
-
return UNKNOWN_USER_CACHE_DIRECTORY;
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
var CRASH_REPORTER_ENTRY = new RegExp(`^(?:Pushary|PusharyMac|pushary-bridge)_${UUID}\\.plist$`);
|
|
325
|
-
var crashReporterEntries = (home = homedir()) => {
|
|
326
|
-
const directory = join(home, "Library", "Application Support", "CrashReporter");
|
|
327
|
-
return namesIn(directory).filter((name) => CRASH_REPORTER_ENTRY.test(name)).map((name) => join(directory, name));
|
|
328
|
-
};
|
|
329
|
-
var storedMacAppState = (home = homedir()) => [
|
|
330
|
-
...macLibraryState(home),
|
|
331
|
-
...macUserCacheState(reportedDarwinUserCacheDirectory()),
|
|
332
|
-
...crashReporterEntries(home)
|
|
333
|
-
];
|
|
334
|
-
var DUMP_SERVICE_LINE = /^\s*"svce"<blob>="(.+)"\s*$/;
|
|
335
|
-
var pusharyKeychainServices = (dump) => {
|
|
336
|
-
const found = /* @__PURE__ */ new Set();
|
|
337
|
-
for (const line of dump.split("\n")) {
|
|
338
|
-
const service = DUMP_SERVICE_LINE.exec(line)?.[1];
|
|
339
|
-
if (service?.startsWith(MAC_KEYCHAIN_SERVICE)) found.add(service);
|
|
340
|
-
}
|
|
341
|
-
return [...found];
|
|
342
|
-
};
|
|
343
|
-
var storedPusharyKeychainServices = () => {
|
|
344
|
-
const dump = execFileSync("security", ["dump-keychain"], {
|
|
345
|
-
encoding: "utf-8",
|
|
346
|
-
timeout: 3e4,
|
|
347
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
348
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
349
|
-
});
|
|
350
|
-
const stored = pusharyKeychainServices(dump);
|
|
351
|
-
return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
|
|
352
|
-
};
|
|
353
|
-
var runningMacAppPIDs = () => {
|
|
354
|
-
if (process.platform !== "darwin") return [];
|
|
355
|
-
try {
|
|
356
|
-
return execSync('pgrep -f "Pushary.app/Contents/MacOS/Pushary"', {
|
|
357
|
-
encoding: "utf-8",
|
|
358
|
-
timeout: 1e4,
|
|
359
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
360
|
-
}).split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0);
|
|
361
|
-
} catch {
|
|
362
|
-
return [];
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
var waitForMacAppExit = (attempts = 20, everyMs = 250) => {
|
|
366
|
-
const idle = new Int32Array(new SharedArrayBuffer(4));
|
|
367
|
-
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
368
|
-
if (runningMacAppPIDs().length === 0) return true;
|
|
369
|
-
Atomics.wait(idle, 0, 0, everyMs);
|
|
370
|
-
}
|
|
371
|
-
return runningMacAppPIDs().length === 0;
|
|
372
|
-
};
|
|
373
|
-
|
|
374
207
|
// src/cli/clean-mac.ts
|
|
375
|
-
import { existsSync
|
|
208
|
+
import { existsSync } from "fs";
|
|
376
209
|
var deleteDefaultsDomain = (guards2, domain) => {
|
|
377
210
|
try {
|
|
378
211
|
guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
|
|
@@ -432,7 +265,7 @@ var removeMacAppState = (guards2, readServices, statePaths, present) => {
|
|
|
432
265
|
if (deleteDefaultsDomain(guards2, domain)) removed++;
|
|
433
266
|
}
|
|
434
267
|
for (const path of statePaths) {
|
|
435
|
-
if (!
|
|
268
|
+
if (!existsSync(path)) continue;
|
|
436
269
|
try {
|
|
437
270
|
guards2.remove(path, { force: true });
|
|
438
271
|
removed++;
|
|
@@ -457,13 +290,13 @@ var quitMacApp = (guards2, state) => {
|
|
|
457
290
|
};
|
|
458
291
|
|
|
459
292
|
// src/cli/editor-extension.ts
|
|
460
|
-
import { existsSync as
|
|
461
|
-
import { homedir
|
|
462
|
-
import { join
|
|
293
|
+
import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
|
|
294
|
+
import { homedir } from "os";
|
|
295
|
+
import { join } from "path";
|
|
463
296
|
var EDITOR_EXTENSION_ID = "pushary.pushary";
|
|
464
297
|
var EDITOR_EXTENSION_DIRS = [
|
|
465
|
-
|
|
466
|
-
|
|
298
|
+
join(".cursor", "extensions"),
|
|
299
|
+
join(".vscode", "extensions")
|
|
467
300
|
];
|
|
468
301
|
var EXTENSIONS_JSON = "extensions.json";
|
|
469
302
|
var isOurEntry = (entry) => {
|
|
@@ -474,7 +307,7 @@ var isOurEntry = (entry) => {
|
|
|
474
307
|
return typeof id === "string" && id.toLowerCase() === EDITOR_EXTENSION_ID;
|
|
475
308
|
};
|
|
476
309
|
var recordWithoutUs = (directory) => {
|
|
477
|
-
const path =
|
|
310
|
+
const path = join(directory, EXTENSIONS_JSON);
|
|
478
311
|
try {
|
|
479
312
|
const entries = JSON.parse(readFileSync(path, "utf-8"));
|
|
480
313
|
if (!Array.isArray(entries)) return void 0;
|
|
@@ -484,15 +317,15 @@ var recordWithoutUs = (directory) => {
|
|
|
484
317
|
return void 0;
|
|
485
318
|
}
|
|
486
319
|
};
|
|
487
|
-
var editorExtensionRemovals = (home =
|
|
488
|
-
const folders =
|
|
320
|
+
var editorExtensionRemovals = (home = homedir()) => EDITOR_EXTENSION_DIRS.map((relative) => join(home, relative)).filter(existsSync2).map((directory) => {
|
|
321
|
+
const folders = readdirSync(directory).filter((name) => name.startsWith(`${EDITOR_EXTENSION_ID}-`)).map((name) => join(directory, name));
|
|
489
322
|
return { directory, folders, record: recordWithoutUs(directory) };
|
|
490
323
|
}).filter((removal) => removal.folders.length > 0 || removal.record !== void 0);
|
|
491
324
|
|
|
492
325
|
// src/cli/skills-store.ts
|
|
493
|
-
import { existsSync as
|
|
494
|
-
import { homedir as
|
|
495
|
-
import { join as
|
|
326
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
327
|
+
import { homedir as homedir2 } from "os";
|
|
328
|
+
import { join as join2 } from "path";
|
|
496
329
|
var SKILLS_STORE_DIR = ".agents";
|
|
497
330
|
var LOCK_FILE = ".skill-lock.json";
|
|
498
331
|
var lockWithoutUs = (path) => {
|
|
@@ -510,26 +343,26 @@ var lockWithoutUs = (path) => {
|
|
|
510
343
|
return void 0;
|
|
511
344
|
}
|
|
512
345
|
};
|
|
513
|
-
var skillsStoreRemoval = (home =
|
|
514
|
-
const store =
|
|
515
|
-
const skillDir =
|
|
516
|
-
const lock = lockWithoutUs(
|
|
346
|
+
var skillsStoreRemoval = (home = homedir2()) => {
|
|
347
|
+
const store = join2(home, SKILLS_STORE_DIR);
|
|
348
|
+
const skillDir = join2(store, "skills", PUSHARY_SKILL_NAME);
|
|
349
|
+
const lock = lockWithoutUs(join2(store, LOCK_FILE));
|
|
517
350
|
return {
|
|
518
|
-
skillDir: lock &&
|
|
351
|
+
skillDir: lock && existsSync3(skillDir) ? skillDir : void 0,
|
|
519
352
|
lock
|
|
520
353
|
};
|
|
521
354
|
};
|
|
522
355
|
|
|
523
356
|
// src/cli/claude-backups.ts
|
|
524
|
-
import { existsSync as
|
|
525
|
-
import { homedir as
|
|
526
|
-
import { join as
|
|
357
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
358
|
+
import { homedir as homedir3 } from "os";
|
|
359
|
+
import { join as join3 } from "path";
|
|
527
360
|
var BACKUP_PREFIX = ".claude.json.backup";
|
|
528
|
-
var claudeJsonBackups = (home =
|
|
529
|
-
const rollingDir =
|
|
530
|
-
const legacy =
|
|
531
|
-
const rolling =
|
|
532
|
-
return
|
|
361
|
+
var claudeJsonBackups = (home = homedir3()) => {
|
|
362
|
+
const rollingDir = join3(home, ".claude", "backups");
|
|
363
|
+
const legacy = join3(home, BACKUP_PREFIX);
|
|
364
|
+
const rolling = existsSync4(rollingDir) ? readdirSync2(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join3(rollingDir, name)) : [];
|
|
365
|
+
return existsSync4(legacy) ? [...rolling, legacy] : rolling;
|
|
533
366
|
};
|
|
534
367
|
var parsed = (path) => {
|
|
535
368
|
try {
|
|
@@ -539,7 +372,7 @@ var parsed = (path) => {
|
|
|
539
372
|
return null;
|
|
540
373
|
}
|
|
541
374
|
};
|
|
542
|
-
var claudeBackupRewrites = (receipt, home =
|
|
375
|
+
var claudeBackupRewrites = (receipt, home = homedir3()) => claudeJsonBackups(home).flatMap((path) => {
|
|
543
376
|
const backup = parsed(path);
|
|
544
377
|
if (!backup) return [];
|
|
545
378
|
const changed = receipt ? restoreClaudeMcpServer(backup, receipt) : removeClaudeMcpServers(backup);
|
|
@@ -585,8 +418,8 @@ var removeGlobalCliPackages = (guards2, request) => {
|
|
|
585
418
|
};
|
|
586
419
|
|
|
587
420
|
// src/cli/config-temp-leftovers.ts
|
|
588
|
-
import { lstatSync, readdirSync as
|
|
589
|
-
import { join as
|
|
421
|
+
import { lstatSync, readdirSync as readdirSync3 } from "fs";
|
|
422
|
+
import { join as join4 } from "path";
|
|
590
423
|
var MAC_APP_WRITE_TEMP = /^\..+\.pushary-[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/;
|
|
591
424
|
var PID_STAMPED_WRITE_TEMP = /^\.\d+-[^/]+\.pushary-tmp$/;
|
|
592
425
|
var CONFIG_TEMP_MIN_AGE_MS = 6e4;
|
|
@@ -594,15 +427,15 @@ var isLeakedConfigTempName = (name) => MAC_APP_WRITE_TEMP.test(name) || PID_STAM
|
|
|
594
427
|
var leakedConfigTemps = (entries, nowMs) => entries.filter((entry) => entry.isFile && isLeakedConfigTempName(entry.name) && nowMs - entry.modifiedAtMs >= CONFIG_TEMP_MIN_AGE_MS).map((entry) => entry.name);
|
|
595
428
|
var directoryEntries = (directory) => {
|
|
596
429
|
try {
|
|
597
|
-
return
|
|
598
|
-
const stats = lstatSync(
|
|
430
|
+
return readdirSync3(directory).flatMap((name) => {
|
|
431
|
+
const stats = lstatSync(join4(directory, name), { throwIfNoEntry: false });
|
|
599
432
|
return stats ? [{ name, isFile: stats.isFile(), modifiedAtMs: stats.mtimeMs }] : [];
|
|
600
433
|
});
|
|
601
434
|
} catch {
|
|
602
435
|
return [];
|
|
603
436
|
}
|
|
604
437
|
};
|
|
605
|
-
var configTempLeftovers = (directories, nowMs) => [...new Set(directories)].flatMap((directory) => leakedConfigTemps(directoryEntries(directory), nowMs).map((name) =>
|
|
438
|
+
var configTempLeftovers = (directories, nowMs) => [...new Set(directories)].flatMap((directory) => leakedConfigTemps(directoryEntries(directory), nowMs).map((name) => join4(directory, name)));
|
|
606
439
|
|
|
607
440
|
// src/app-owned-paths.ts
|
|
608
441
|
var APP_OWNED_ENTRIES = [
|
|
@@ -699,13 +532,13 @@ var CURSOR_PLUGIN_DIR = cursorPluginDir();
|
|
|
699
532
|
var CURSOR_USER_HOOKS = cursorUserHooks();
|
|
700
533
|
var VSCODE_PLUGIN_DIR = vscodePluginDir();
|
|
701
534
|
var PUSHARY_DIR = pusharyDir();
|
|
702
|
-
var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) =>
|
|
535
|
+
var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join5(homedir4(), f));
|
|
703
536
|
var PRESENCE_BY_RESOLUTION = {
|
|
704
537
|
bundle: "present",
|
|
705
538
|
missing: "gone",
|
|
706
539
|
"no-stub": "absent"
|
|
707
540
|
};
|
|
708
|
-
var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(
|
|
541
|
+
var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(join5(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY), liveBridgeProbe()).kind];
|
|
709
542
|
var removalScope = (keepMcpServer, keepAppWiring) => ({
|
|
710
543
|
keepAppWiring,
|
|
711
544
|
keepMcpServer
|
|
@@ -740,7 +573,7 @@ var guardedRemove = (path, options) => guards.remove(path, options);
|
|
|
740
573
|
var cursorPluginLeftovers = () => {
|
|
741
574
|
const parent = dirname(CURSOR_PLUGIN_DIR);
|
|
742
575
|
try {
|
|
743
|
-
return
|
|
576
|
+
return readdirSync4(parent).filter(isCursorPluginLeftover).map((name) => join5(parent, name));
|
|
744
577
|
} catch {
|
|
745
578
|
return [];
|
|
746
579
|
}
|
|
@@ -754,14 +587,14 @@ var guardedDaemonRemoval = async () => {
|
|
|
754
587
|
};
|
|
755
588
|
var guardedInstructionBlockRemoval = (path) => {
|
|
756
589
|
if (!dryRun) return removeInstructionBlock(path);
|
|
757
|
-
if (!
|
|
590
|
+
if (!existsSync5(path)) return false;
|
|
758
591
|
const hasBlock = readFileSync4(path, "utf-8").includes("pushary");
|
|
759
592
|
if (hasBlock) wouldNote("rewrite", path);
|
|
760
593
|
return hasBlock;
|
|
761
594
|
};
|
|
762
595
|
var guardedAliasRemoval = () => {
|
|
763
596
|
if (!dryRun) return removeClaudeAlias();
|
|
764
|
-
const shells = CANDIDATE_RCS.map((name) =>
|
|
597
|
+
const shells = CANDIDATE_RCS.map((name) => join5(homedir4(), name)).filter((path) => existsSync5(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
|
|
765
598
|
for (const path of shells) wouldNote("rewrite", path);
|
|
766
599
|
return shells;
|
|
767
600
|
};
|
|
@@ -786,7 +619,7 @@ var removeFxInstructions = () => {
|
|
|
786
619
|
}
|
|
787
620
|
};
|
|
788
621
|
var removeCursorUserHook = (scope) => {
|
|
789
|
-
if (!
|
|
622
|
+
if (!existsSync5(CURSOR_USER_HOOKS)) return "absent";
|
|
790
623
|
let parsed2;
|
|
791
624
|
try {
|
|
792
625
|
parsed2 = JSON.parse(readFileSync4(CURSOR_USER_HOOKS, "utf-8"));
|
|
@@ -831,14 +664,14 @@ var cleanSettingsFile = (path, label, scope) => {
|
|
|
831
664
|
);
|
|
832
665
|
};
|
|
833
666
|
var agentConfigDirectories = () => [
|
|
834
|
-
|
|
667
|
+
homedir4(),
|
|
835
668
|
dirname(CLAUDE_SETTINGS),
|
|
836
669
|
dirname(codexConfigToml()),
|
|
837
670
|
dirname(geminiSettings()),
|
|
838
671
|
dirname(CURSOR_USER_HOOKS),
|
|
839
672
|
openCodeConfigDir(),
|
|
840
673
|
fxConfigDir(),
|
|
841
|
-
...vscodeSettingsTargets(
|
|
674
|
+
...vscodeSettingsTargets(existsSync5).map((settings) => dirname(settings))
|
|
842
675
|
];
|
|
843
676
|
var restoreTakeoverReceipts = () => {
|
|
844
677
|
const targets = [
|
|
@@ -846,15 +679,15 @@ var restoreTakeoverReceipts = () => {
|
|
|
846
679
|
["codex", codexHooksJson(), codexConfigToml(), "mcp_servers", "toml"],
|
|
847
680
|
["gemini_cli", geminiSettings(), geminiSettings(), "mcpServers", "json"],
|
|
848
681
|
["cursor", CURSOR_USER_HOOKS, null, null, null],
|
|
849
|
-
["vscode",
|
|
682
|
+
["vscode", join5(VSCODE_PLUGIN_DIR, "hooks", "hooks.json"), vscodePluginMcp(), "mcpServers", "json"]
|
|
850
683
|
];
|
|
851
684
|
for (const [agent, hookFile, mcpFile, mcpKey, mcpFormat] of targets) {
|
|
852
685
|
const receiptPath = hookTakeoverReceipt(agent);
|
|
853
|
-
if (!
|
|
686
|
+
if (!existsSync5(receiptPath)) continue;
|
|
854
687
|
try {
|
|
855
688
|
const receipt = readJson(receiptPath);
|
|
856
689
|
if (!isHookTakeoverReceipt(receipt) || receipt.agent !== agent) throw new Error("invalid receipt");
|
|
857
|
-
const document =
|
|
690
|
+
const document = existsSync5(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
|
|
858
691
|
if (!document || typeof document !== "object" || Array.isArray(document)) throw new Error("invalid hooks file");
|
|
859
692
|
const appAlreadyOwns = hookOwnerOf(document) === "app";
|
|
860
693
|
const cliPositions = agent === "codex" ? codexHookPositions(document) : {};
|
|
@@ -865,7 +698,7 @@ var restoreTakeoverReceipts = () => {
|
|
|
865
698
|
if (mcpFile === hookFile) {
|
|
866
699
|
mcpDocument = document;
|
|
867
700
|
} else {
|
|
868
|
-
const raw =
|
|
701
|
+
const raw = existsSync5(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
|
|
869
702
|
mcpDocument = raw.trim() ? mcpFormat === "toml" ? parseTOML(raw) : JSON.parse(raw) : {};
|
|
870
703
|
}
|
|
871
704
|
mcpChanged = restoreMcpServer(mcpDocument, mcpKey, receipt.mcpServer);
|
|
@@ -875,7 +708,7 @@ var restoreTakeoverReceipts = () => {
|
|
|
875
708
|
if (!appAlreadyOwns && agent === "codex") {
|
|
876
709
|
if (!mcpDocument) {
|
|
877
710
|
const configPath = codexConfigToml();
|
|
878
|
-
const raw =
|
|
711
|
+
const raw = existsSync5(configPath) ? readFileSync4(configPath, "utf-8") : "";
|
|
879
712
|
mcpDocument = raw.trim() ? parseTOML(raw) : {};
|
|
880
713
|
}
|
|
881
714
|
codexConfig = mcpDocument;
|
|
@@ -971,7 +804,7 @@ var main = async () => {
|
|
|
971
804
|
}
|
|
972
805
|
if (presence !== "absent") console.log();
|
|
973
806
|
const restoredByTakeover = new Set(
|
|
974
|
-
["claude_code", "codex", "gemini_cli"].filter((agent) =>
|
|
807
|
+
["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync5(hookTakeoverReceipt(agent)))
|
|
975
808
|
);
|
|
976
809
|
if (keepShared) restoreTakeoverReceipts();
|
|
977
810
|
const sharedMcpKeys = {
|
|
@@ -997,10 +830,11 @@ var main = async () => {
|
|
|
997
830
|
let macAppKeepsCodexAppCards = false;
|
|
998
831
|
if (uid !== void 0) {
|
|
999
832
|
try {
|
|
1000
|
-
const
|
|
1001
|
-
|
|
833
|
+
const removal = { homeDir: homedir4(), uid, keepWhatTheMacAppTurnedOn: keepShared, dryRun };
|
|
834
|
+
const appCards = removeCodexAppCardsFromThisMac(removal);
|
|
835
|
+
macAppKeepsCodexAppCards = codexAppCardsFolderStaysOnThisMac(removal);
|
|
1002
836
|
if (appCards === "removed") console.log(` ${check} Codex app cards ${dim(did("removed"))} ${dim("(quit Codex and open it again)")}`);
|
|
1003
|
-
if (
|
|
837
|
+
if (appCards === "kept_for_the_mac_app") console.log(` ${skip} Codex app cards ${dim("(turned on by the Mac app; left on)")}`);
|
|
1004
838
|
} catch {
|
|
1005
839
|
incompleteClean = true;
|
|
1006
840
|
console.log(` ${cross} Codex app cards ${dim("(could not turn off; run pushary codex --app-cards off)")}`);
|
|
@@ -1013,7 +847,7 @@ var main = async () => {
|
|
|
1013
847
|
const claudeHadPusharyEntry = claudeHasPusharyEntry();
|
|
1014
848
|
const rawReceipt = readJson(CLAUDE_MCP_RECEIPT);
|
|
1015
849
|
const receipt = isClaudeMcpSnapshot(rawReceipt) ? rawReceipt : null;
|
|
1016
|
-
const receiptUnreadable =
|
|
850
|
+
const receiptUnreadable = existsSync5(CLAUDE_MCP_RECEIPT) && !receipt;
|
|
1017
851
|
if (keepClaudeMcp) {
|
|
1018
852
|
console.log(` ${skip} Claude Code MCP servers ${dim("(kept: the Mac app uses it)")}`);
|
|
1019
853
|
} else if (claudeJson2) {
|
|
@@ -1028,7 +862,7 @@ var main = async () => {
|
|
|
1028
862
|
if (receipt && !keepShared) incompleteClean = true;
|
|
1029
863
|
console.log(` ${skip} Claude Code MCP servers ${dim(receipt ? "(changed after setup; left unchanged)" : "(no pushary entries)")}`);
|
|
1030
864
|
}
|
|
1031
|
-
} else if (
|
|
865
|
+
} else if (existsSync5(CLAUDE_MCP_RECEIPT)) {
|
|
1032
866
|
incompleteClean = true;
|
|
1033
867
|
console.log(` ${skip} Claude Code MCP servers ${dim("(config missing; setup receipt kept for retry)")}`);
|
|
1034
868
|
} else {
|
|
@@ -1072,7 +906,7 @@ var main = async () => {
|
|
|
1072
906
|
}
|
|
1073
907
|
if (cursorGate === "failed") {
|
|
1074
908
|
console.log(` ${skip} Cursor plugin ${dim("(kept: removing it now would block matched commands)")}`);
|
|
1075
|
-
} else if (
|
|
909
|
+
} else if (existsSync5(CURSOR_PLUGIN_DIR)) {
|
|
1076
910
|
guardedRemove(CURSOR_PLUGIN_DIR);
|
|
1077
911
|
console.log(` ${check} Cursor plugin ${dim("(removed from ~/.cursor/plugins/local)")}`);
|
|
1078
912
|
} else {
|
|
@@ -1088,9 +922,9 @@ var main = async () => {
|
|
|
1088
922
|
if (keepShared) {
|
|
1089
923
|
console.log(` ${skip} VS Code plugin ${dim("(kept: the Mac app writes the same plugin directory)")}`);
|
|
1090
924
|
}
|
|
1091
|
-
for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(
|
|
925
|
+
for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync5)) {
|
|
1092
926
|
const label = `VS Code plugin ${dim(`(${shortenHome(settingsPath)})`)}`;
|
|
1093
|
-
if (!
|
|
927
|
+
if (!existsSync5(settingsPath)) {
|
|
1094
928
|
console.log(` ${skip} ${label} ${dim("(no settings.json)")}`);
|
|
1095
929
|
continue;
|
|
1096
930
|
}
|
|
@@ -1104,7 +938,7 @@ var main = async () => {
|
|
|
1104
938
|
console.log(` ${skip} ${label} ${dim("(no pushary entry)")}`);
|
|
1105
939
|
}
|
|
1106
940
|
}
|
|
1107
|
-
if (!keepShared &&
|
|
941
|
+
if (!keepShared && existsSync5(VSCODE_PLUGIN_DIR)) {
|
|
1108
942
|
guardedRemove(VSCODE_PLUGIN_DIR);
|
|
1109
943
|
console.log(` ${check} VS Code plugin files ${dim(did("removed"))}`);
|
|
1110
944
|
}
|
|
@@ -1123,7 +957,7 @@ var main = async () => {
|
|
|
1123
957
|
}
|
|
1124
958
|
if (keepShared) {
|
|
1125
959
|
console.log(` ${skip} Skill directory ${dim("(kept: the Mac app uses it)")}`);
|
|
1126
|
-
} else if (
|
|
960
|
+
} else if (existsSync5(SKILL_DIR)) {
|
|
1127
961
|
guardedRemove(SKILL_DIR);
|
|
1128
962
|
console.log(` ${check} Skill directory ${dim(did("removed"))}`);
|
|
1129
963
|
} else {
|
|
@@ -1183,7 +1017,7 @@ var main = async () => {
|
|
|
1183
1017
|
const codexSkillDir2 = codexSkillDir();
|
|
1184
1018
|
if (keepShared) {
|
|
1185
1019
|
console.log(` ${skip} Codex skill directory ${dim("(kept: the Mac app uses it)")}`);
|
|
1186
|
-
} else if (
|
|
1020
|
+
} else if (existsSync5(codexSkillDir2)) {
|
|
1187
1021
|
guardedRemove(codexSkillDir2);
|
|
1188
1022
|
console.log(` ${check} Codex skill directory ${dim(did("removed"))}`);
|
|
1189
1023
|
} else {
|
|
@@ -1236,7 +1070,7 @@ var main = async () => {
|
|
|
1236
1070
|
console.log(` ${skip} Gemini GEMINI.md ${dim("(no pushary block)")}`);
|
|
1237
1071
|
}
|
|
1238
1072
|
const openCodePlugin = openCodePluginFile();
|
|
1239
|
-
const openCodePluginContents =
|
|
1073
|
+
const openCodePluginContents = existsSync5(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
|
|
1240
1074
|
if (openCodePluginContents === null) {
|
|
1241
1075
|
console.log(` ${skip} OpenCode plugin ${dim("(not installed)")}`);
|
|
1242
1076
|
} else if (!isOpenCodePluginOurs(openCodePluginContents)) {
|
|
@@ -1246,15 +1080,15 @@ var main = async () => {
|
|
|
1246
1080
|
} else {
|
|
1247
1081
|
guardedRemove(openCodePlugin, { force: true });
|
|
1248
1082
|
console.log(` ${check} OpenCode plugin ${dim(did("removed"))}`);
|
|
1249
|
-
const sibling =
|
|
1083
|
+
const sibling = join5(openCodePluginDir(), OPENCODE_PLUGIN_SIBLING);
|
|
1250
1084
|
const remaining = (() => {
|
|
1251
1085
|
try {
|
|
1252
|
-
return
|
|
1086
|
+
return readdirSync4(openCodePluginDir()).filter((name) => name !== OPENCODE_PLUGIN_SIBLING);
|
|
1253
1087
|
} catch {
|
|
1254
1088
|
return [];
|
|
1255
1089
|
}
|
|
1256
1090
|
})();
|
|
1257
|
-
const siblingIsOurs =
|
|
1091
|
+
const siblingIsOurs = existsSync5(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
|
|
1258
1092
|
if (siblingIsOurs && !hasForeignPlugins(remaining)) {
|
|
1259
1093
|
guardedRemove(sibling, { force: true });
|
|
1260
1094
|
console.log(` ${check} OpenCode plugin sibling ${dim(did("removed"))}`);
|
|
@@ -1307,7 +1141,7 @@ var main = async () => {
|
|
|
1307
1141
|
}
|
|
1308
1142
|
}
|
|
1309
1143
|
}
|
|
1310
|
-
} else if (
|
|
1144
|
+
} else if (existsSync5(HERMES_CONFIG_RECEIPT)) {
|
|
1311
1145
|
incompleteClean = true;
|
|
1312
1146
|
console.log(` ${skip} Hermes ${dim("(runtime not found; setup receipt kept for retry)")}`);
|
|
1313
1147
|
} else {
|
|
@@ -1356,15 +1190,15 @@ var main = async () => {
|
|
|
1356
1190
|
if (leakedTemps.length > 0) {
|
|
1357
1191
|
console.log(` ${check} Leftover temp files ${dim(`(${dryRun ? "would remove" : "removed"} ${leakedTemps.length} left by an interrupted config write)`)}`);
|
|
1358
1192
|
}
|
|
1359
|
-
if (
|
|
1193
|
+
if (existsSync5(PUSHARY_DIR)) {
|
|
1360
1194
|
let removed = 0;
|
|
1361
1195
|
const kept = [];
|
|
1362
|
-
for (const entry of
|
|
1196
|
+
for (const entry of readdirSync4(PUSHARY_DIR)) {
|
|
1363
1197
|
if (keepShared && isAppOwned(entry) || entry === "setup" && (keepShared || incompleteClean) || entry === CODEX_APP_CARDS_DIRECTORY && macAppKeepsCodexAppCards) {
|
|
1364
1198
|
kept.push(entry);
|
|
1365
1199
|
continue;
|
|
1366
1200
|
}
|
|
1367
|
-
guardedRemove(
|
|
1201
|
+
guardedRemove(join5(PUSHARY_DIR, entry), { force: true });
|
|
1368
1202
|
removed++;
|
|
1369
1203
|
}
|
|
1370
1204
|
if (removed > 0) {
|
|
@@ -1381,10 +1215,10 @@ var main = async () => {
|
|
|
1381
1215
|
}
|
|
1382
1216
|
try {
|
|
1383
1217
|
let swept = 0;
|
|
1384
|
-
for (const f of
|
|
1218
|
+
for (const f of readdirSync4(tmpdir())) {
|
|
1385
1219
|
if (!f.startsWith("pushary-")) continue;
|
|
1386
1220
|
try {
|
|
1387
|
-
guardedRemove(
|
|
1221
|
+
guardedRemove(join5(tmpdir(), f), { force: true });
|
|
1388
1222
|
swept++;
|
|
1389
1223
|
} catch {
|
|
1390
1224
|
}
|
|
@@ -1438,7 +1272,7 @@ var main = async () => {
|
|
|
1438
1272
|
console.log(` ${dim("Still stuck? Send this output to")} ${SUPPORT_EMAIL} ${dim("or")} ${SUPPORT_DISCORD}`);
|
|
1439
1273
|
} else if (everything) {
|
|
1440
1274
|
console.log(` ${green(bold("Clean complete. Nothing of ours is left in any agent config."))}`);
|
|
1441
|
-
const bundle = installedPusharyBundles().find(
|
|
1275
|
+
const bundle = installedPusharyBundles().find(existsSync5);
|
|
1442
1276
|
if (bundle) {
|
|
1443
1277
|
console.log(` ${dim("The app itself is still installed. Drag")} ${bundle} ${dim("to the Trash to finish.")}`);
|
|
1444
1278
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
letCodexRunWithoutPushary
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-E46NE7FB.js";
|
|
5
5
|
|
|
6
6
|
// bin/pushary-codex-session.ts
|
|
7
7
|
var args = process.argv.slice(2);
|
|
@@ -16,7 +16,7 @@ var desktopAccount = async () => {
|
|
|
16
16
|
return null;
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
-
var desktopLaunch = await import("../codex-desktop-launch-
|
|
19
|
+
var desktopLaunch = await import("../codex-desktop-launch-RIBIFXSF.js").catch(() => null);
|
|
20
20
|
if (desktopLaunch === null && appBehindTheProxy !== void 0) {
|
|
21
21
|
process.exitCode = await letCodexRunWithoutPushary(appBehindTheProxy, args.slice(3));
|
|
22
22
|
} else {
|
|
@@ -24,7 +24,7 @@ if (desktopLaunch === null && appBehindTheProxy !== void 0) {
|
|
|
24
24
|
const stop = () => abort.abort();
|
|
25
25
|
if (!args[0]?.startsWith("--desktop")) for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(signal, stop);
|
|
26
26
|
try {
|
|
27
|
-
const { codexDesktopCommand } = desktopLaunch ?? await import("../codex-desktop-launch-
|
|
27
|
+
const { codexDesktopCommand } = desktopLaunch ?? await import("../codex-desktop-launch-RIBIFXSF.js");
|
|
28
28
|
const desktop = await codexDesktopCommand(args, [process.execPath, ...process.execArgv, process.argv[1], "codex"], desktopAccount);
|
|
29
29
|
if (desktop !== null) process.exitCode = desktop;
|
|
30
30
|
else {
|