nexora-code 1.0.3 → 1.0.5
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/dist/bundle.cjs +610 -2
- package/package.json +2 -2
- package/scripts/desktop/config.cjs +36 -0
- package/scripts/desktop/linux.cjs +15 -8
- package/scripts/desktop/macos.cjs +23 -18
- package/scripts/desktop/postinstall.cjs +6 -3
- package/scripts/desktop/preuninstall.cjs +4 -6
- package/scripts/desktop/shortcut.cjs +14 -12
- package/scripts/desktop/windows-wt-profile.cjs +100 -0
- package/scripts/desktop/windows.cjs +110 -55
package/dist/bundle.cjs
CHANGED
|
@@ -7085,7 +7085,7 @@ var init_string_width = __esm({
|
|
|
7085
7085
|
init_get_east_asian_width();
|
|
7086
7086
|
import_emoji_regex = __toESM(require_emoji_regex(), 1);
|
|
7087
7087
|
segmenter = new Intl.Segmenter();
|
|
7088
|
-
defaultIgnorableCodePointRegex =
|
|
7088
|
+
defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
7089
7089
|
}
|
|
7090
7090
|
});
|
|
7091
7091
|
|
|
@@ -284542,6 +284542,594 @@ var init_archiver = __esm({
|
|
|
284542
284542
|
}
|
|
284543
284543
|
});
|
|
284544
284544
|
|
|
284545
|
+
// scripts/desktop/config.cjs
|
|
284546
|
+
var require_config = __commonJS({
|
|
284547
|
+
"scripts/desktop/config.cjs"(exports2, module2) {
|
|
284548
|
+
"use strict";
|
|
284549
|
+
var path55 = require("path");
|
|
284550
|
+
function getNexoraConfig() {
|
|
284551
|
+
try {
|
|
284552
|
+
const pkgPath = path55.resolve(__dirname, "../../package.json");
|
|
284553
|
+
const pkg = require(pkgPath);
|
|
284554
|
+
let binName = "nexora";
|
|
284555
|
+
if (typeof pkg.bin === "string") {
|
|
284556
|
+
binName = pkg.name;
|
|
284557
|
+
} else if (typeof pkg.bin === "object" && pkg.bin !== null) {
|
|
284558
|
+
binName = Object.keys(pkg.bin)[0];
|
|
284559
|
+
}
|
|
284560
|
+
return {
|
|
284561
|
+
binName,
|
|
284562
|
+
displayName: "Nexora Code",
|
|
284563
|
+
description: "Launch Nexora Code AI Workspace"
|
|
284564
|
+
};
|
|
284565
|
+
} catch {
|
|
284566
|
+
return {
|
|
284567
|
+
binName: "nexora",
|
|
284568
|
+
displayName: "Nexora Code",
|
|
284569
|
+
description: "Launch Nexora Code AI Workspace"
|
|
284570
|
+
};
|
|
284571
|
+
}
|
|
284572
|
+
}
|
|
284573
|
+
module2.exports = { getNexoraConfig };
|
|
284574
|
+
}
|
|
284575
|
+
});
|
|
284576
|
+
|
|
284577
|
+
// scripts/desktop/windows-wt-profile.cjs
|
|
284578
|
+
var require_windows_wt_profile = __commonJS({
|
|
284579
|
+
"scripts/desktop/windows-wt-profile.cjs"(exports2, module2) {
|
|
284580
|
+
"use strict";
|
|
284581
|
+
var fs51 = require("fs");
|
|
284582
|
+
var path55 = require("path");
|
|
284583
|
+
function getWTSettingsPath() {
|
|
284584
|
+
const localAppData = process.env.LOCALAPPDATA || "";
|
|
284585
|
+
const candidates = [
|
|
284586
|
+
// Store version
|
|
284587
|
+
path55.join(localAppData, "Packages", "Microsoft.WindowsTerminal_8wekyb3d8bbwe", "LocalState", "settings.json"),
|
|
284588
|
+
// Preview version
|
|
284589
|
+
path55.join(localAppData, "Packages", "Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe", "LocalState", "settings.json"),
|
|
284590
|
+
// Winget / scoop version
|
|
284591
|
+
path55.join(localAppData, "Microsoft", "Windows Terminal", "settings.json")
|
|
284592
|
+
];
|
|
284593
|
+
return candidates.find((p) => {
|
|
284594
|
+
try {
|
|
284595
|
+
fs51.accessSync(p);
|
|
284596
|
+
return true;
|
|
284597
|
+
} catch {
|
|
284598
|
+
return false;
|
|
284599
|
+
}
|
|
284600
|
+
}) || null;
|
|
284601
|
+
}
|
|
284602
|
+
var { execSync: execSync5 } = require("child_process");
|
|
284603
|
+
var { getNexoraConfig } = require_config();
|
|
284604
|
+
async function resolveNexoraAbsolutePath(binName) {
|
|
284605
|
+
try {
|
|
284606
|
+
const result = execSync5(`where ${binName}`, { stdio: "pipe" }).toString().trim().split("\n")[0].trim();
|
|
284607
|
+
if (result) return result;
|
|
284608
|
+
} catch {
|
|
284609
|
+
}
|
|
284610
|
+
try {
|
|
284611
|
+
const prefix = execSync5("npm config get prefix", { stdio: "pipe" }).toString().trim();
|
|
284612
|
+
const candidate = path55.join(prefix, `${binName}.cmd`);
|
|
284613
|
+
fs51.accessSync(candidate);
|
|
284614
|
+
return candidate;
|
|
284615
|
+
} catch {
|
|
284616
|
+
}
|
|
284617
|
+
throw new Error(
|
|
284618
|
+
`${binName}.cmd not found. Ensure "npm install -g nexora-code" completed successfully.`
|
|
284619
|
+
);
|
|
284620
|
+
}
|
|
284621
|
+
function detectBestShell(binName) {
|
|
284622
|
+
try {
|
|
284623
|
+
execSync5("where pwsh.exe", { stdio: "pipe" });
|
|
284624
|
+
return { shellExe: "pwsh.exe" };
|
|
284625
|
+
} catch {
|
|
284626
|
+
}
|
|
284627
|
+
return {
|
|
284628
|
+
shellExe: "powershell.exe"
|
|
284629
|
+
};
|
|
284630
|
+
}
|
|
284631
|
+
async function repairWTProfile() {
|
|
284632
|
+
const settingsPath = getWTSettingsPath();
|
|
284633
|
+
if (!settingsPath) return;
|
|
284634
|
+
let settings;
|
|
284635
|
+
try {
|
|
284636
|
+
const raw = fs51.readFileSync(settingsPath, "utf-8");
|
|
284637
|
+
const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
284638
|
+
settings = JSON.parse(stripped);
|
|
284639
|
+
} catch {
|
|
284640
|
+
return;
|
|
284641
|
+
}
|
|
284642
|
+
const profiles = settings?.profiles?.list;
|
|
284643
|
+
if (!Array.isArray(profiles)) return;
|
|
284644
|
+
let modified = false;
|
|
284645
|
+
for (const profile of profiles) {
|
|
284646
|
+
const { binName } = getNexoraConfig();
|
|
284647
|
+
if (profile.name === "Nexora Code" && (profile.commandline === "nexora-code" || profile.commandline === binName)) {
|
|
284648
|
+
const { shellExe } = detectBestShell(binName);
|
|
284649
|
+
const nexoraAbs = await resolveNexoraAbsolutePath(binName);
|
|
284650
|
+
profile.commandline = `${shellExe} -NoExit -Command "& '${nexoraAbs.replace(/\\/g, "\\\\").replace(/'/g, "''")}'"`;
|
|
284651
|
+
modified = true;
|
|
284652
|
+
console.log(" \u2713 Repaired corrupted Windows Terminal profile.");
|
|
284653
|
+
console.log(` \u2713 Fixed commandline \u2192 ${profile.commandline}`);
|
|
284654
|
+
}
|
|
284655
|
+
}
|
|
284656
|
+
if (modified) {
|
|
284657
|
+
fs51.writeFileSync(settingsPath, JSON.stringify(settings, null, 4), "utf-8");
|
|
284658
|
+
}
|
|
284659
|
+
}
|
|
284660
|
+
module2.exports = { repairWTProfile, resolveNexoraAbsolutePath };
|
|
284661
|
+
}
|
|
284662
|
+
});
|
|
284663
|
+
|
|
284664
|
+
// scripts/desktop/windows.cjs
|
|
284665
|
+
var require_windows2 = __commonJS({
|
|
284666
|
+
"scripts/desktop/windows.cjs"(exports2, module2) {
|
|
284667
|
+
"use strict";
|
|
284668
|
+
var { execSync: execSync5 } = require("child_process");
|
|
284669
|
+
var path55 = require("path");
|
|
284670
|
+
var fs51 = require("fs");
|
|
284671
|
+
var os18 = require("os");
|
|
284672
|
+
var { repairWTProfile, resolveNexoraAbsolutePath } = require_windows_wt_profile();
|
|
284673
|
+
var { getNexoraConfig } = require_config();
|
|
284674
|
+
function detectWindowsTerminal() {
|
|
284675
|
+
try {
|
|
284676
|
+
const wtPath = execSync5("where wt.exe", { stdio: "pipe" }).toString().trim().split("\n")[0].trim();
|
|
284677
|
+
if (wtPath) {
|
|
284678
|
+
try {
|
|
284679
|
+
execSync5("where pwsh.exe", { stdio: "pipe" });
|
|
284680
|
+
return { label: "Windows Terminal + PowerShell 7", shellExe: wtPath, innerShell: "pwsh.exe" };
|
|
284681
|
+
} catch {
|
|
284682
|
+
return { label: "Windows Terminal + PowerShell 5", shellExe: wtPath, innerShell: "powershell.exe" };
|
|
284683
|
+
}
|
|
284684
|
+
}
|
|
284685
|
+
} catch {
|
|
284686
|
+
}
|
|
284687
|
+
try {
|
|
284688
|
+
const pwsh7 = execSync5("where pwsh.exe", { stdio: "pipe" }).toString().trim().split("\n")[0].trim();
|
|
284689
|
+
if (pwsh7) return { label: "PowerShell 7", shellExe: pwsh7, innerShell: null };
|
|
284690
|
+
} catch {
|
|
284691
|
+
}
|
|
284692
|
+
const ps5 = path55.join(process.env.SystemRoot || "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
284693
|
+
return { label: "PowerShell 5", shellExe: ps5, innerShell: null };
|
|
284694
|
+
}
|
|
284695
|
+
async function createWindowsShortcut(ctx) {
|
|
284696
|
+
await repairWTProfile();
|
|
284697
|
+
const { binName, displayName, description } = getNexoraConfig();
|
|
284698
|
+
let nexoraAbsPath;
|
|
284699
|
+
try {
|
|
284700
|
+
nexoraAbsPath = await resolveNexoraAbsolutePath(binName);
|
|
284701
|
+
console.log(` \u2713 Binary found at : ${nexoraAbsPath}`);
|
|
284702
|
+
} catch (err6) {
|
|
284703
|
+
console.log(` \u2717 ${err6.message}`);
|
|
284704
|
+
return;
|
|
284705
|
+
}
|
|
284706
|
+
const shortcutPath = path55.join(ctx.desktopPath, `${displayName}.lnk`);
|
|
284707
|
+
const iconPath = path55.join(ctx.iconDir, "icon.ico");
|
|
284708
|
+
const iconExists = fs51.existsSync(iconPath);
|
|
284709
|
+
const terminal2 = detectWindowsTerminal();
|
|
284710
|
+
let targetExe, shortcutArgs;
|
|
284711
|
+
if (terminal2.innerShell) {
|
|
284712
|
+
targetExe = terminal2.shellExe;
|
|
284713
|
+
shortcutArgs = `${terminal2.innerShell} -NoExit -Command "& '${nexoraAbsPath}'"`;
|
|
284714
|
+
} else {
|
|
284715
|
+
targetExe = terminal2.shellExe;
|
|
284716
|
+
shortcutArgs = `-NoExit -Command "& '${nexoraAbsPath}'"`;
|
|
284717
|
+
}
|
|
284718
|
+
const ps1Lines = [
|
|
284719
|
+
`$ws = New-Object -ComObject WScript.Shell`,
|
|
284720
|
+
`$sc = $ws.CreateShortcut(@"`,
|
|
284721
|
+
shortcutPath,
|
|
284722
|
+
`"@)`,
|
|
284723
|
+
`$sc.TargetPath = @"`,
|
|
284724
|
+
targetExe,
|
|
284725
|
+
`"@`,
|
|
284726
|
+
`$sc.Arguments = @"`,
|
|
284727
|
+
shortcutArgs,
|
|
284728
|
+
`"@`,
|
|
284729
|
+
`$sc.WorkingDirectory = $env:USERPROFILE`,
|
|
284730
|
+
`$sc.Description = @"`,
|
|
284731
|
+
description,
|
|
284732
|
+
`"@`
|
|
284733
|
+
];
|
|
284734
|
+
if (iconExists) {
|
|
284735
|
+
ps1Lines.push(`$sc.IconLocation = @"`, iconPath, `"@`);
|
|
284736
|
+
}
|
|
284737
|
+
ps1Lines.push(`$sc.Save()`);
|
|
284738
|
+
const ps1Content = ps1Lines.join("\r\n") + "\r\n";
|
|
284739
|
+
const ps1Path = path55.join(os18.tmpdir(), `nexora-shortcut-${Date.now()}.ps1`);
|
|
284740
|
+
try {
|
|
284741
|
+
fs51.writeFileSync(ps1Path, ps1Content, "utf-8");
|
|
284742
|
+
execSync5(
|
|
284743
|
+
`powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${ps1Path}"`,
|
|
284744
|
+
{ stdio: "pipe", timeout: 2e4 }
|
|
284745
|
+
);
|
|
284746
|
+
console.log(` \u2713 Desktop shortcut : ${shortcutPath}`);
|
|
284747
|
+
console.log(` \u2713 Terminal : ${terminal2.label}`);
|
|
284748
|
+
console.log(` \u2713 Launches : ${binName}`);
|
|
284749
|
+
if (iconExists) console.log(` \u2713 Icon applied : Nexora Code logo`);
|
|
284750
|
+
console.log("");
|
|
284751
|
+
console.log(` \u2192 Double-click "${displayName}" on your Desktop to launch!`);
|
|
284752
|
+
console.log("");
|
|
284753
|
+
} catch (err6) {
|
|
284754
|
+
throw new Error(`Windows .lnk creation failed: ${err6.message}`);
|
|
284755
|
+
} finally {
|
|
284756
|
+
try {
|
|
284757
|
+
fs51.unlinkSync(ps1Path);
|
|
284758
|
+
} catch {
|
|
284759
|
+
}
|
|
284760
|
+
}
|
|
284761
|
+
}
|
|
284762
|
+
function removeWindowsShortcut(ctx) {
|
|
284763
|
+
const { displayName } = getNexoraConfig();
|
|
284764
|
+
const shortcutPath = path55.join(ctx.desktopPath, `${displayName}.lnk`);
|
|
284765
|
+
try {
|
|
284766
|
+
fs51.unlinkSync(shortcutPath);
|
|
284767
|
+
console.log(` \u2713 Desktop shortcut removed: ${displayName}.lnk`);
|
|
284768
|
+
} catch {
|
|
284769
|
+
}
|
|
284770
|
+
}
|
|
284771
|
+
module2.exports = { createWindowsShortcut, removeWindowsShortcut };
|
|
284772
|
+
}
|
|
284773
|
+
});
|
|
284774
|
+
|
|
284775
|
+
// scripts/desktop/macos.cjs
|
|
284776
|
+
var require_macos = __commonJS({
|
|
284777
|
+
"scripts/desktop/macos.cjs"(exports2, module2) {
|
|
284778
|
+
"use strict";
|
|
284779
|
+
var { execSync: execSync5 } = require("child_process");
|
|
284780
|
+
var path55 = require("path");
|
|
284781
|
+
var fs51 = require("fs");
|
|
284782
|
+
var { getNexoraConfig } = require_config();
|
|
284783
|
+
function buildMacTerminalScript(binName) {
|
|
284784
|
+
if (fs51.existsSync("/Applications/iTerm.app")) {
|
|
284785
|
+
return `#!/bin/bash
|
|
284786
|
+
open -a iTerm -- bash -c "${binName}; exec bash"
|
|
284787
|
+
`;
|
|
284788
|
+
}
|
|
284789
|
+
if (fs51.existsSync("/Applications/Warp.app")) {
|
|
284790
|
+
return `#!/bin/bash
|
|
284791
|
+
open -a Warp
|
|
284792
|
+
osascript -e 'tell application "Warp" to activate'
|
|
284793
|
+
`;
|
|
284794
|
+
}
|
|
284795
|
+
if (fs51.existsSync("/Applications/Hyper.app")) {
|
|
284796
|
+
return `#!/bin/bash
|
|
284797
|
+
open -a Hyper
|
|
284798
|
+
`;
|
|
284799
|
+
}
|
|
284800
|
+
return `#!/bin/bash
|
|
284801
|
+
osascript <<'APPLESCRIPT'
|
|
284802
|
+
tell application "Terminal"
|
|
284803
|
+
activate
|
|
284804
|
+
do script "${binName}"
|
|
284805
|
+
end tell
|
|
284806
|
+
APPLESCRIPT
|
|
284807
|
+
`;
|
|
284808
|
+
}
|
|
284809
|
+
function buildPlist(hasIcon, displayName) {
|
|
284810
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
284811
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
284812
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
284813
|
+
<plist version="1.0">
|
|
284814
|
+
<dict>
|
|
284815
|
+
<key>CFBundleExecutable</key>
|
|
284816
|
+
<string>nexora-launcher</string>
|
|
284817
|
+
<key>CFBundleIdentifier</key>
|
|
284818
|
+
<string>cloud.getnexora.code</string>
|
|
284819
|
+
<key>CFBundleName</key>
|
|
284820
|
+
<string>${displayName}</string>
|
|
284821
|
+
<key>CFBundleDisplayName</key>
|
|
284822
|
+
<string>${displayName}</string>
|
|
284823
|
+
<key>CFBundleVersion</key>
|
|
284824
|
+
<string>1.0.0</string>
|
|
284825
|
+
<key>CFBundleShortVersionString</key>
|
|
284826
|
+
<string>1.0.0</string>
|
|
284827
|
+
<key>CFBundlePackageType</key>
|
|
284828
|
+
<string>APPL</string>
|
|
284829
|
+
${hasIcon ? "<key>CFBundleIconFile</key>\n <string>AppIcon</string>" : ""}
|
|
284830
|
+
<key>LSMinimumSystemVersion</key>
|
|
284831
|
+
<string>11.0</string>
|
|
284832
|
+
<key>NSHighResolutionCapable</key>
|
|
284833
|
+
<true/>
|
|
284834
|
+
<key>LSUIElement</key>
|
|
284835
|
+
<false/>
|
|
284836
|
+
</dict>
|
|
284837
|
+
</plist>
|
|
284838
|
+
`;
|
|
284839
|
+
}
|
|
284840
|
+
function createMacosShortcut(ctx) {
|
|
284841
|
+
const { binName, displayName } = getNexoraConfig();
|
|
284842
|
+
const appBundlePath = path55.join(ctx.desktopPath, `${displayName}.app`);
|
|
284843
|
+
const macOSDir = path55.join(appBundlePath, "Contents", "MacOS");
|
|
284844
|
+
const resourceDir = path55.join(appBundlePath, "Contents", "Resources");
|
|
284845
|
+
const icnsPath = path55.join(ctx.iconDir, "icon.icns");
|
|
284846
|
+
const hasIcon = fs51.existsSync(icnsPath);
|
|
284847
|
+
fs51.mkdirSync(macOSDir, { recursive: true });
|
|
284848
|
+
fs51.mkdirSync(resourceDir, { recursive: true });
|
|
284849
|
+
const launcherContent = buildMacTerminalScript(binName);
|
|
284850
|
+
const launcherPath = path55.join(macOSDir, "nexora-launcher");
|
|
284851
|
+
fs51.writeFileSync(launcherPath, launcherContent, "utf-8");
|
|
284852
|
+
fs51.chmodSync(launcherPath, 493);
|
|
284853
|
+
fs51.writeFileSync(
|
|
284854
|
+
path55.join(appBundlePath, "Contents", "Info.plist"),
|
|
284855
|
+
buildPlist(hasIcon, displayName),
|
|
284856
|
+
"utf-8"
|
|
284857
|
+
);
|
|
284858
|
+
if (hasIcon) {
|
|
284859
|
+
fs51.copyFileSync(icnsPath, path55.join(resourceDir, "AppIcon.icns"));
|
|
284860
|
+
}
|
|
284861
|
+
try {
|
|
284862
|
+
execSync5(`xattr -dr com.apple.quarantine "${appBundlePath}"`, { stdio: "pipe" });
|
|
284863
|
+
} catch {
|
|
284864
|
+
}
|
|
284865
|
+
try {
|
|
284866
|
+
execSync5(`touch "${appBundlePath}"`, { stdio: "pipe" });
|
|
284867
|
+
} catch {
|
|
284868
|
+
}
|
|
284869
|
+
console.log(` \u2713 App bundle created: ${appBundlePath}`);
|
|
284870
|
+
createCommandFallback(ctx.desktopPath, displayName, binName);
|
|
284871
|
+
console.log("");
|
|
284872
|
+
console.log(` \u2192 Double-click "${displayName}" on your Desktop to launch Nexora!`);
|
|
284873
|
+
console.log("");
|
|
284874
|
+
}
|
|
284875
|
+
function createCommandFallback(desktopPath, displayName, binName) {
|
|
284876
|
+
const commandPath = path55.join(desktopPath, `${displayName} (Terminal).command`);
|
|
284877
|
+
const commandContent = `#!/bin/bash
|
|
284878
|
+
clear
|
|
284879
|
+
${binName}
|
|
284880
|
+
exec $SHELL
|
|
284881
|
+
`;
|
|
284882
|
+
fs51.writeFileSync(commandPath, commandContent, "utf-8");
|
|
284883
|
+
fs51.chmodSync(commandPath, 493);
|
|
284884
|
+
console.log(` \u2713 .command fallback: ${commandPath}`);
|
|
284885
|
+
}
|
|
284886
|
+
function removeMacosShortcut(ctx) {
|
|
284887
|
+
const { binName, displayName } = getNexoraConfig();
|
|
284888
|
+
const targets = [
|
|
284889
|
+
path55.join(ctx.desktopPath, `${displayName}.app`),
|
|
284890
|
+
path55.join(ctx.desktopPath, `${displayName} (Terminal).command`),
|
|
284891
|
+
// Remove old defaults just in case
|
|
284892
|
+
path55.join(ctx.desktopPath, "Nexora Code.app"),
|
|
284893
|
+
path55.join(ctx.desktopPath, "Nexora Code (Terminal).command")
|
|
284894
|
+
];
|
|
284895
|
+
for (const t of targets) {
|
|
284896
|
+
try {
|
|
284897
|
+
fs51.rmSync(t, { recursive: true, force: true });
|
|
284898
|
+
console.log(` \u2713 Removed: ${t}`);
|
|
284899
|
+
} catch {
|
|
284900
|
+
}
|
|
284901
|
+
}
|
|
284902
|
+
}
|
|
284903
|
+
module2.exports = { createMacosShortcut, removeMacosShortcut };
|
|
284904
|
+
}
|
|
284905
|
+
});
|
|
284906
|
+
|
|
284907
|
+
// scripts/desktop/linux.cjs
|
|
284908
|
+
var require_linux = __commonJS({
|
|
284909
|
+
"scripts/desktop/linux.cjs"(exports2, module2) {
|
|
284910
|
+
"use strict";
|
|
284911
|
+
var { execSync: execSync5 } = require("child_process");
|
|
284912
|
+
var path55 = require("path");
|
|
284913
|
+
var fs51 = require("fs");
|
|
284914
|
+
var { getNexoraConfig } = require_config();
|
|
284915
|
+
var TERMINAL_CANDIDATES = [
|
|
284916
|
+
{ bin: "gnome-terminal", args: '-- bash -c "nexora-code; exec bash"' },
|
|
284917
|
+
{ bin: "konsole", args: '-e bash -c "nexora-code; exec bash"' },
|
|
284918
|
+
{ bin: "xfce4-terminal", args: `--command="bash -c 'nexora-code; exec bash'"` },
|
|
284919
|
+
{ bin: "tilix", args: `-e "bash -c 'nexora-code; exec bash'"` },
|
|
284920
|
+
{ bin: "alacritty", args: '-e bash -c "nexora-code; exec bash"' },
|
|
284921
|
+
{ bin: "kitty", args: 'bash -c "nexora-code; exec bash"' },
|
|
284922
|
+
{ bin: "xterm", args: '-e "nexora-code; bash"' },
|
|
284923
|
+
{ bin: "x-terminal-emulator", args: '-e bash -c "nexora-code; exec bash"' }
|
|
284924
|
+
// Debian/Ubuntu alias
|
|
284925
|
+
];
|
|
284926
|
+
function detectLinuxTerminal() {
|
|
284927
|
+
for (const candidate of TERMINAL_CANDIDATES) {
|
|
284928
|
+
try {
|
|
284929
|
+
execSync5(`which ${candidate.bin}`, { stdio: "pipe" });
|
|
284930
|
+
return candidate;
|
|
284931
|
+
} catch {
|
|
284932
|
+
continue;
|
|
284933
|
+
}
|
|
284934
|
+
}
|
|
284935
|
+
return null;
|
|
284936
|
+
}
|
|
284937
|
+
function createLinuxShortcut(ctx) {
|
|
284938
|
+
const { binName, displayName, description } = getNexoraConfig();
|
|
284939
|
+
const terminal2 = detectLinuxTerminal();
|
|
284940
|
+
const iconPath = path55.join(ctx.iconDir, "icon.png");
|
|
284941
|
+
const iconExists = fs51.existsSync(iconPath);
|
|
284942
|
+
const execLine = terminal2 ? `${terminal2.bin} ${terminal2.args.replace(/nexora-code/g, binName)}` : binName;
|
|
284943
|
+
const iconLine = iconExists ? iconPath : "utilities-terminal";
|
|
284944
|
+
const desktopContent = [
|
|
284945
|
+
"[Desktop Entry]",
|
|
284946
|
+
"Version=1.0",
|
|
284947
|
+
"Type=Application",
|
|
284948
|
+
`Name=${displayName}`,
|
|
284949
|
+
"GenericName=AI Developer Workspace",
|
|
284950
|
+
`Comment=${description}`,
|
|
284951
|
+
`Exec=${execLine}`,
|
|
284952
|
+
`Icon=${iconLine}`,
|
|
284953
|
+
"Terminal=false",
|
|
284954
|
+
// false: the terminal emulator handles this
|
|
284955
|
+
"StartupNotify=true",
|
|
284956
|
+
"Categories=Development;IDE;",
|
|
284957
|
+
`Keywords=${binName};code;ai;developer;assistant;cli;`,
|
|
284958
|
+
`StartupWMClass=${binName}`
|
|
284959
|
+
].join("\n") + "\n";
|
|
284960
|
+
const desktopFilePath = path55.join(ctx.desktopPath, "nexora-code.desktop");
|
|
284961
|
+
fs51.writeFileSync(desktopFilePath, desktopContent, "utf-8");
|
|
284962
|
+
fs51.chmodSync(desktopFilePath, 493);
|
|
284963
|
+
console.log(` \u2713 Desktop launcher: ${desktopFilePath}`);
|
|
284964
|
+
const appMenuDir = path55.join(ctx.realHomeDir, ".local", "share", "applications");
|
|
284965
|
+
const appMenuPath = path55.join(appMenuDir, "nexora-code.desktop");
|
|
284966
|
+
try {
|
|
284967
|
+
fs51.mkdirSync(appMenuDir, { recursive: true });
|
|
284968
|
+
fs51.writeFileSync(appMenuPath, desktopContent, "utf-8");
|
|
284969
|
+
fs51.chmodSync(appMenuPath, 493);
|
|
284970
|
+
console.log(` \u2713 App menu entry: ${appMenuPath}`);
|
|
284971
|
+
try {
|
|
284972
|
+
execSync5("update-desktop-database ~/.local/share/applications", { stdio: "pipe" });
|
|
284973
|
+
} catch {
|
|
284974
|
+
}
|
|
284975
|
+
} catch (err6) {
|
|
284976
|
+
console.log(` \u26A0 App menu entry skipped: ${err6.message}`);
|
|
284977
|
+
}
|
|
284978
|
+
if (terminal2) {
|
|
284979
|
+
console.log(` \u2713 Terminal detected: ${terminal2.bin}`);
|
|
284980
|
+
} else {
|
|
284981
|
+
console.log(" \u26A0 No terminal emulator detected \u2014 using system default.");
|
|
284982
|
+
}
|
|
284983
|
+
console.log("");
|
|
284984
|
+
console.log(` \u2192 Double-click the icon on your Desktop to launch ${displayName}!`);
|
|
284985
|
+
if (!terminal2) {
|
|
284986
|
+
console.log(` \u2192 Or run "${binName}" directly in your terminal.`);
|
|
284987
|
+
}
|
|
284988
|
+
console.log("");
|
|
284989
|
+
}
|
|
284990
|
+
function removeLinuxShortcut(ctx) {
|
|
284991
|
+
const { binName } = getNexoraConfig();
|
|
284992
|
+
const targets = [
|
|
284993
|
+
path55.join(ctx.desktopPath, "nexora-code.desktop"),
|
|
284994
|
+
path55.join(ctx.realHomeDir, ".local", "share", "applications", "nexora-code.desktop"),
|
|
284995
|
+
// Also remove using the new displayName or binName if applicable
|
|
284996
|
+
path55.join(ctx.desktopPath, `${binName}.desktop`),
|
|
284997
|
+
path55.join(ctx.realHomeDir, ".local", "share", "applications", `${binName}.desktop`)
|
|
284998
|
+
];
|
|
284999
|
+
for (const t of targets) {
|
|
285000
|
+
try {
|
|
285001
|
+
fs51.unlinkSync(t);
|
|
285002
|
+
console.log(` \u2713 Removed: ${t}`);
|
|
285003
|
+
} catch {
|
|
285004
|
+
}
|
|
285005
|
+
}
|
|
285006
|
+
try {
|
|
285007
|
+
execSync5("update-desktop-database ~/.local/share/applications", { stdio: "pipe" });
|
|
285008
|
+
} catch {
|
|
285009
|
+
}
|
|
285010
|
+
}
|
|
285011
|
+
module2.exports = { createLinuxShortcut, removeLinuxShortcut };
|
|
285012
|
+
}
|
|
285013
|
+
});
|
|
285014
|
+
|
|
285015
|
+
// scripts/desktop/shortcut.cjs
|
|
285016
|
+
var require_shortcut = __commonJS({
|
|
285017
|
+
"scripts/desktop/shortcut.cjs"(exports2, module2) {
|
|
285018
|
+
"use strict";
|
|
285019
|
+
var os18 = require("os");
|
|
285020
|
+
var path55 = require("path");
|
|
285021
|
+
var fs51 = require("fs");
|
|
285022
|
+
function fileExistsSync(p) {
|
|
285023
|
+
try {
|
|
285024
|
+
fs51.accessSync(p);
|
|
285025
|
+
return true;
|
|
285026
|
+
} catch {
|
|
285027
|
+
return false;
|
|
285028
|
+
}
|
|
285029
|
+
}
|
|
285030
|
+
function getRealHomeDir() {
|
|
285031
|
+
if (process.env.SUDO_USER) {
|
|
285032
|
+
const plat = process.platform;
|
|
285033
|
+
if (plat === "linux") return `/home/${process.env.SUDO_USER}`;
|
|
285034
|
+
if (plat === "darwin") return `/Users/${process.env.SUDO_USER}`;
|
|
285035
|
+
}
|
|
285036
|
+
return process.env.USERPROFILE || process.env.HOME || os18.homedir();
|
|
285037
|
+
}
|
|
285038
|
+
function findDesktopPath(homeDir, platform2) {
|
|
285039
|
+
const candidates = [];
|
|
285040
|
+
if (platform2 === "windows") {
|
|
285041
|
+
candidates.push(
|
|
285042
|
+
path55.join(homeDir, "Desktop"),
|
|
285043
|
+
path55.join(homeDir, "OneDrive", "Desktop"),
|
|
285044
|
+
// Very common on Win11 + OneDrive
|
|
285045
|
+
path55.join(homeDir, "OneDrive - Personal", "Desktop")
|
|
285046
|
+
);
|
|
285047
|
+
} else if (platform2 === "macos") {
|
|
285048
|
+
candidates.push(path55.join(homeDir, "Desktop"));
|
|
285049
|
+
} else {
|
|
285050
|
+
const xdgDesktop = process.env.XDG_DESKTOP_DIR;
|
|
285051
|
+
if (xdgDesktop) candidates.push(xdgDesktop);
|
|
285052
|
+
candidates.push(
|
|
285053
|
+
path55.join(homeDir, "Desktop"),
|
|
285054
|
+
path55.join(homeDir, "Escritorio"),
|
|
285055
|
+
// Spanish
|
|
285056
|
+
path55.join(homeDir, "Bureau"),
|
|
285057
|
+
// French
|
|
285058
|
+
path55.join(homeDir, "Schreibtisch"),
|
|
285059
|
+
// German
|
|
285060
|
+
path55.join(homeDir, "\u30C7\u30B9\u30AF\u30C8\u30C3\u30D7"),
|
|
285061
|
+
// Japanese
|
|
285062
|
+
path55.join(homeDir, "\u684C\u9762")
|
|
285063
|
+
// Chinese (Simplified)
|
|
285064
|
+
);
|
|
285065
|
+
}
|
|
285066
|
+
for (const candidate of candidates) {
|
|
285067
|
+
if (fileExistsSync(candidate)) return candidate;
|
|
285068
|
+
}
|
|
285069
|
+
return null;
|
|
285070
|
+
}
|
|
285071
|
+
function getPackageDir() {
|
|
285072
|
+
return path55.resolve(__dirname, "..", "..");
|
|
285073
|
+
}
|
|
285074
|
+
function buildUserContext() {
|
|
285075
|
+
const rawPlatform = process.platform;
|
|
285076
|
+
const platform2 = rawPlatform === "win32" ? "windows" : rawPlatform === "darwin" ? "macos" : "linux";
|
|
285077
|
+
const realHomeDir = getRealHomeDir();
|
|
285078
|
+
const desktopPath = findDesktopPath(realHomeDir, platform2);
|
|
285079
|
+
const packageDir = getPackageDir();
|
|
285080
|
+
const iconDir = path55.join(packageDir, "assets");
|
|
285081
|
+
const { binName } = require_config().getNexoraConfig();
|
|
285082
|
+
const binaryName = platform2 === "windows" ? `${binName}.cmd` : binName;
|
|
285083
|
+
const npmBinDir = path55.dirname(process.execPath);
|
|
285084
|
+
const binaryPath = path55.join(npmBinDir, binaryName);
|
|
285085
|
+
return { platform: platform2, realHomeDir, desktopPath, packageDir, binaryPath, iconDir };
|
|
285086
|
+
}
|
|
285087
|
+
async function createShortcut() {
|
|
285088
|
+
const ctx = buildUserContext();
|
|
285089
|
+
if (!ctx.desktopPath) {
|
|
285090
|
+
const { binName } = require_config().getNexoraConfig();
|
|
285091
|
+
console.log(" \u2139 No desktop found (headless / server / WSL environment).");
|
|
285092
|
+
console.log(` Run "${binName}" in any terminal to start.`);
|
|
285093
|
+
return;
|
|
285094
|
+
}
|
|
285095
|
+
console.log("");
|
|
285096
|
+
console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
285097
|
+
console.log(" \u2502 Nexora Code \u2014 Desktop Shortcut Setup \u2502");
|
|
285098
|
+
console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
285099
|
+
console.log("");
|
|
285100
|
+
switch (ctx.platform) {
|
|
285101
|
+
case "windows":
|
|
285102
|
+
await require_windows2().createWindowsShortcut(ctx);
|
|
285103
|
+
break;
|
|
285104
|
+
case "macos":
|
|
285105
|
+
await require_macos().createMacosShortcut(ctx);
|
|
285106
|
+
break;
|
|
285107
|
+
case "linux":
|
|
285108
|
+
await require_linux().createLinuxShortcut(ctx);
|
|
285109
|
+
break;
|
|
285110
|
+
default:
|
|
285111
|
+
console.log(" \u26A0 Unrecognised platform \u2014 skipping shortcut creation.");
|
|
285112
|
+
}
|
|
285113
|
+
}
|
|
285114
|
+
async function removeShortcut() {
|
|
285115
|
+
const ctx = buildUserContext();
|
|
285116
|
+
if (!ctx.desktopPath) return;
|
|
285117
|
+
switch (ctx.platform) {
|
|
285118
|
+
case "windows":
|
|
285119
|
+
await require_windows2().removeWindowsShortcut(ctx);
|
|
285120
|
+
break;
|
|
285121
|
+
case "macos":
|
|
285122
|
+
await require_macos().removeMacosShortcut(ctx);
|
|
285123
|
+
break;
|
|
285124
|
+
case "linux":
|
|
285125
|
+
await require_linux().removeLinuxShortcut(ctx);
|
|
285126
|
+
break;
|
|
285127
|
+
}
|
|
285128
|
+
}
|
|
285129
|
+
module2.exports = { createShortcut, removeShortcut, buildUserContext };
|
|
285130
|
+
}
|
|
285131
|
+
});
|
|
285132
|
+
|
|
284545
285133
|
// node_modules/pdfjs-dist/legacy/build/pdf.mjs
|
|
284546
285134
|
var pdf_exports = {};
|
|
284547
285135
|
__export(pdf_exports, {
|
|
@@ -318475,7 +319063,7 @@ function updateNotifier(options) {
|
|
|
318475
319063
|
// package.json
|
|
318476
319064
|
var package_default = {
|
|
318477
319065
|
name: "nexora-code",
|
|
318478
|
-
version: "1.0.
|
|
319066
|
+
version: "1.0.5",
|
|
318479
319067
|
description: "Nexora Code \u2014 World-Class AI Coding Agent CLI. BYOK \xB7 51 tools \xB7 Multi-action \xB7 Streaming \xB7 Session Memory",
|
|
318480
319068
|
author: "Enoch Boadu",
|
|
318481
319069
|
license: "MIT",
|
|
@@ -332837,6 +333425,13 @@ function loadProjectMemory() {
|
|
|
332837
333425
|
// src/index.ts
|
|
332838
333426
|
init_headless();
|
|
332839
333427
|
init_keychain();
|
|
333428
|
+
import_node_process51.default.removeAllListeners("warning");
|
|
333429
|
+
import_node_process51.default.on("warning", (warning) => {
|
|
333430
|
+
if (warning.name === "ExperimentalWarning") return;
|
|
333431
|
+
import_node_process51.default.stderr.write(`
|
|
333432
|
+
Warning: ${warning.message}
|
|
333433
|
+
`);
|
|
333434
|
+
});
|
|
332840
333435
|
var VERSION2 = package_default.version || "0.0.0";
|
|
332841
333436
|
import_node_process51.default.on("SIGINT", () => {
|
|
332842
333437
|
console.log(`
|
|
@@ -332861,6 +333456,19 @@ var args = import_node_process51.default.argv.slice(2);
|
|
|
332861
333456
|
var subcommand = args[0]?.toLowerCase();
|
|
332862
333457
|
var headless2 = args.includes("--headless");
|
|
332863
333458
|
async function main2() {
|
|
333459
|
+
if (args.includes("--repair-shortcut")) {
|
|
333460
|
+
const { createShortcut, removeShortcut } = await Promise.resolve().then(() => __toESM(require_shortcut(), 1));
|
|
333461
|
+
console.log("\n Nexora Code \u2014 Repairing desktop shortcut...\n");
|
|
333462
|
+
try {
|
|
333463
|
+
await removeShortcut();
|
|
333464
|
+
await createShortcut();
|
|
333465
|
+
console.log("\n \u2713 Shortcut repaired successfully.\n");
|
|
333466
|
+
import_node_process51.default.exit(0);
|
|
333467
|
+
} catch (err6) {
|
|
333468
|
+
console.error("\n \u2717 Repair failed:", err6.message);
|
|
333469
|
+
import_node_process51.default.exit(1);
|
|
333470
|
+
}
|
|
333471
|
+
}
|
|
332864
333472
|
const taskIdIndex = args.indexOf("--task-id");
|
|
332865
333473
|
if (taskIdIndex !== -1 && args[taskIdIndex + 1]) {
|
|
332866
333474
|
await runBackgroundWorker(args[taskIdIndex + 1]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexora-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Nexora Code — World-Class AI Coding Agent CLI. BYOK · 51 tools · Multi-action · Streaming · Session Memory",
|
|
5
5
|
"author": "Enoch Boadu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -94,4 +94,4 @@
|
|
|
94
94
|
"workspaces": [
|
|
95
95
|
"packages/*"
|
|
96
96
|
]
|
|
97
|
-
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function getNexoraConfig() {
|
|
6
|
+
try {
|
|
7
|
+
const pkgPath = path.resolve(__dirname, '../../package.json');
|
|
8
|
+
const pkg = require(pkgPath);
|
|
9
|
+
|
|
10
|
+
// Extract the first key from the bin field — that's the terminal command
|
|
11
|
+
let binName = 'nexora'; // fallback
|
|
12
|
+
|
|
13
|
+
if (typeof pkg.bin === 'string') {
|
|
14
|
+
// "bin": "./dist/index.js" — use package name as command
|
|
15
|
+
binName = pkg.name;
|
|
16
|
+
} else if (typeof pkg.bin === 'object' && pkg.bin !== null) {
|
|
17
|
+
// "bin": { "nexora": "./dist/index.js" } — use the key
|
|
18
|
+
binName = Object.keys(pkg.bin)[0];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
binName,
|
|
23
|
+
displayName: 'Nexora Code',
|
|
24
|
+
description: 'Launch Nexora Code AI Workspace',
|
|
25
|
+
};
|
|
26
|
+
} catch {
|
|
27
|
+
// If package.json can't be read, fall back to known correct value
|
|
28
|
+
return {
|
|
29
|
+
binName: 'nexora',
|
|
30
|
+
displayName: 'Nexora Code',
|
|
31
|
+
description: 'Launch Nexora Code AI Workspace',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { getNexoraConfig };
|
|
@@ -8,6 +8,8 @@ const { execSync } = require('child_process');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
|
|
11
|
+
const { getNexoraConfig } = require('./config.cjs');
|
|
12
|
+
|
|
11
13
|
// Ordered by quality of terminal experience (best first)
|
|
12
14
|
const TERMINAL_CANDIDATES = [
|
|
13
15
|
{ bin: 'gnome-terminal', args: '-- bash -c "nexora-code; exec bash"' },
|
|
@@ -38,14 +40,15 @@ function detectLinuxTerminal() {
|
|
|
38
40
|
* Creates a .desktop launcher on the desktop and in the app menu.
|
|
39
41
|
*/
|
|
40
42
|
function createLinuxShortcut(ctx) {
|
|
43
|
+
const { binName, displayName, description } = getNexoraConfig();
|
|
41
44
|
const terminal = detectLinuxTerminal();
|
|
42
45
|
const iconPath = path.join(ctx.iconDir, 'icon.png');
|
|
43
46
|
const iconExists = fs.existsSync(iconPath);
|
|
44
47
|
|
|
45
48
|
// XDG .desktop file spec
|
|
46
49
|
const execLine = terminal
|
|
47
|
-
? `${terminal.bin} ${terminal.args}`
|
|
48
|
-
:
|
|
50
|
+
? `${terminal.bin} ${terminal.args.replace(/nexora-code/g, binName)}`
|
|
51
|
+
: binName; // Last resort: hope $TERM is set and system opens a terminal
|
|
49
52
|
|
|
50
53
|
const iconLine = iconExists ? iconPath : 'utilities-terminal';
|
|
51
54
|
|
|
@@ -53,16 +56,16 @@ function createLinuxShortcut(ctx) {
|
|
|
53
56
|
'[Desktop Entry]',
|
|
54
57
|
'Version=1.0',
|
|
55
58
|
'Type=Application',
|
|
56
|
-
|
|
59
|
+
`Name=${displayName}`,
|
|
57
60
|
'GenericName=AI Developer Workspace',
|
|
58
|
-
|
|
61
|
+
`Comment=${description}`,
|
|
59
62
|
`Exec=${execLine}`,
|
|
60
63
|
`Icon=${iconLine}`,
|
|
61
64
|
'Terminal=false', // false: the terminal emulator handles this
|
|
62
65
|
'StartupNotify=true',
|
|
63
66
|
'Categories=Development;IDE;',
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
`Keywords=${binName};code;ai;developer;assistant;cli;`,
|
|
68
|
+
`StartupWMClass=${binName}`,
|
|
66
69
|
].join('\n') + '\n';
|
|
67
70
|
|
|
68
71
|
// 1. Desktop icon
|
|
@@ -95,9 +98,9 @@ function createLinuxShortcut(ctx) {
|
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
console.log('');
|
|
98
|
-
console.log(
|
|
101
|
+
console.log(` → Double-click the icon on your Desktop to launch ${displayName}!`);
|
|
99
102
|
if (!terminal) {
|
|
100
|
-
console.log(
|
|
103
|
+
console.log(` → Or run "${binName}" directly in your terminal.`);
|
|
101
104
|
}
|
|
102
105
|
console.log('');
|
|
103
106
|
}
|
|
@@ -106,9 +109,13 @@ function createLinuxShortcut(ctx) {
|
|
|
106
109
|
* Removes all Nexora Code shortcut files on Linux.
|
|
107
110
|
*/
|
|
108
111
|
function removeLinuxShortcut(ctx) {
|
|
112
|
+
const { binName } = getNexoraConfig();
|
|
109
113
|
const targets = [
|
|
110
114
|
path.join(ctx.desktopPath, 'nexora-code.desktop'),
|
|
111
115
|
path.join(ctx.realHomeDir, '.local', 'share', 'applications', 'nexora-code.desktop'),
|
|
116
|
+
// Also remove using the new displayName or binName if applicable
|
|
117
|
+
path.join(ctx.desktopPath, `${binName}.desktop`),
|
|
118
|
+
path.join(ctx.realHomeDir, '.local', 'share', 'applications', `${binName}.desktop`),
|
|
112
119
|
];
|
|
113
120
|
|
|
114
121
|
for (const t of targets) {
|
|
@@ -8,16 +8,16 @@ const { execSync } = require('child_process');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const { getNexoraConfig } = require('./config.cjs');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Detect best terminal on macOS.
|
|
14
|
+
* Detect best terminal on macOS and build launch script.
|
|
15
15
|
* Priority: iTerm2 > Warp > Hyper > Terminal.app (always available)
|
|
16
16
|
*/
|
|
17
|
-
function
|
|
17
|
+
function buildMacTerminalScript(binName) {
|
|
18
18
|
if (fs.existsSync('/Applications/iTerm.app')) {
|
|
19
19
|
return `#!/bin/bash
|
|
20
|
-
open -a iTerm -- bash -c "
|
|
20
|
+
open -a iTerm -- bash -c "${binName}; exec bash"
|
|
21
21
|
`;
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -41,7 +41,7 @@ open -a Hyper
|
|
|
41
41
|
osascript <<'APPLESCRIPT'
|
|
42
42
|
tell application "Terminal"
|
|
43
43
|
activate
|
|
44
|
-
do script "
|
|
44
|
+
do script "${binName}"
|
|
45
45
|
end tell
|
|
46
46
|
APPLESCRIPT
|
|
47
47
|
`;
|
|
@@ -50,7 +50,7 @@ APPLESCRIPT
|
|
|
50
50
|
/**
|
|
51
51
|
* Builds the Info.plist content for the .app bundle.
|
|
52
52
|
*/
|
|
53
|
-
function buildPlist(hasIcon) {
|
|
53
|
+
function buildPlist(hasIcon, displayName) {
|
|
54
54
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
55
55
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
56
56
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -61,9 +61,9 @@ function buildPlist(hasIcon) {
|
|
|
61
61
|
<key>CFBundleIdentifier</key>
|
|
62
62
|
<string>cloud.getnexora.code</string>
|
|
63
63
|
<key>CFBundleName</key>
|
|
64
|
-
<string>${
|
|
64
|
+
<string>${displayName}</string>
|
|
65
65
|
<key>CFBundleDisplayName</key>
|
|
66
|
-
<string>${
|
|
66
|
+
<string>${displayName}</string>
|
|
67
67
|
<key>CFBundleVersion</key>
|
|
68
68
|
<string>1.0.0</string>
|
|
69
69
|
<key>CFBundleShortVersionString</key>
|
|
@@ -94,7 +94,8 @@ function buildPlist(hasIcon) {
|
|
|
94
94
|
* AppIcon.icns (optional)
|
|
95
95
|
*/
|
|
96
96
|
function createMacosShortcut(ctx) {
|
|
97
|
-
const
|
|
97
|
+
const { binName, displayName } = getNexoraConfig();
|
|
98
|
+
const appBundlePath = path.join(ctx.desktopPath, `${displayName}.app`);
|
|
98
99
|
const macOSDir = path.join(appBundlePath, 'Contents', 'MacOS');
|
|
99
100
|
const resourceDir = path.join(appBundlePath, 'Contents', 'Resources');
|
|
100
101
|
const icnsPath = path.join(ctx.iconDir, 'icon.icns');
|
|
@@ -105,7 +106,7 @@ function createMacosShortcut(ctx) {
|
|
|
105
106
|
fs.mkdirSync(resourceDir, { recursive: true });
|
|
106
107
|
|
|
107
108
|
// Write launcher script
|
|
108
|
-
const launcherContent =
|
|
109
|
+
const launcherContent = buildMacTerminalScript(binName);
|
|
109
110
|
const launcherPath = path.join(macOSDir, 'nexora-launcher');
|
|
110
111
|
fs.writeFileSync(launcherPath, launcherContent, 'utf-8');
|
|
111
112
|
fs.chmodSync(launcherPath, 0o755);
|
|
@@ -113,7 +114,7 @@ function createMacosShortcut(ctx) {
|
|
|
113
114
|
// Write Info.plist
|
|
114
115
|
fs.writeFileSync(
|
|
115
116
|
path.join(appBundlePath, 'Contents', 'Info.plist'),
|
|
116
|
-
buildPlist(hasIcon),
|
|
117
|
+
buildPlist(hasIcon, displayName),
|
|
117
118
|
'utf-8'
|
|
118
119
|
);
|
|
119
120
|
|
|
@@ -131,19 +132,19 @@ function createMacosShortcut(ctx) {
|
|
|
131
132
|
console.log(` ✓ App bundle created: ${appBundlePath}`);
|
|
132
133
|
|
|
133
134
|
// Also create a simpler .command file as a backup for users who prefer it
|
|
134
|
-
createCommandFallback(ctx.desktopPath);
|
|
135
|
+
createCommandFallback(ctx.desktopPath, displayName, binName);
|
|
135
136
|
|
|
136
137
|
console.log('');
|
|
137
|
-
console.log(` → Double-click "${
|
|
138
|
+
console.log(` → Double-click "${displayName}" on your Desktop to launch Nexora!`);
|
|
138
139
|
console.log('');
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
/**
|
|
142
143
|
* Creates a fallback .command script (simpler than .app, but always works).
|
|
143
144
|
*/
|
|
144
|
-
function createCommandFallback(desktopPath) {
|
|
145
|
-
const commandPath = path.join(desktopPath, `${
|
|
146
|
-
const commandContent = `#!/bin/bash\nclear\
|
|
145
|
+
function createCommandFallback(desktopPath, displayName, binName) {
|
|
146
|
+
const commandPath = path.join(desktopPath, `${displayName} (Terminal).command`);
|
|
147
|
+
const commandContent = `#!/bin/bash\nclear\n${binName}\nexec $SHELL\n`;
|
|
147
148
|
fs.writeFileSync(commandPath, commandContent, 'utf-8');
|
|
148
149
|
fs.chmodSync(commandPath, 0o755);
|
|
149
150
|
console.log(` ✓ .command fallback: ${commandPath}`);
|
|
@@ -153,9 +154,13 @@ function createCommandFallback(desktopPath) {
|
|
|
153
154
|
* Removes all Nexora Code shortcut files on macOS.
|
|
154
155
|
*/
|
|
155
156
|
function removeMacosShortcut(ctx) {
|
|
157
|
+
const { binName, displayName } = getNexoraConfig();
|
|
156
158
|
const targets = [
|
|
157
|
-
path.join(ctx.desktopPath, `${
|
|
158
|
-
path.join(ctx.desktopPath, `${
|
|
159
|
+
path.join(ctx.desktopPath, `${displayName}.app`),
|
|
160
|
+
path.join(ctx.desktopPath, `${displayName} (Terminal).command`),
|
|
161
|
+
// Remove old defaults just in case
|
|
162
|
+
path.join(ctx.desktopPath, 'Nexora Code.app'),
|
|
163
|
+
path.join(ctx.desktopPath, 'Nexora Code (Terminal).command'),
|
|
159
164
|
];
|
|
160
165
|
|
|
161
166
|
for (const t of targets) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
const { createShortcut } = require('./shortcut.cjs');
|
|
13
13
|
|
|
14
|
-
function main() {
|
|
14
|
+
async function main() {
|
|
15
15
|
// ── Guard 1: Only run on global installs (-g flag) ──────────────────────────
|
|
16
16
|
// npm sets npm_config_global=true for `npm install -g` commands.
|
|
17
17
|
// Local `npm install` inside the project does NOT set this.
|
|
@@ -34,7 +34,10 @@ function main() {
|
|
|
34
34
|
process.exit(0);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
createShortcut();
|
|
37
|
+
await createShortcut();
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
main()
|
|
40
|
+
main().catch(err => {
|
|
41
|
+
// Never let shortcut errors break the install
|
|
42
|
+
process.exit(0);
|
|
43
|
+
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const { removeShortcut } = require('./shortcut.cjs');
|
|
10
10
|
|
|
11
|
-
function main() {
|
|
11
|
+
async function main() {
|
|
12
12
|
// Only clean up after global uninstalls — not local dev uninstalls
|
|
13
13
|
const isGlobalUninstall = process.env.npm_config_global === 'true';
|
|
14
14
|
if (!isGlobalUninstall) {
|
|
@@ -17,13 +17,11 @@ function main() {
|
|
|
17
17
|
|
|
18
18
|
console.log('');
|
|
19
19
|
console.log(' Nexora Code — Cleaning up desktop shortcut...');
|
|
20
|
-
removeShortcut();
|
|
20
|
+
await removeShortcut();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// Never let cleanup errors break the uninstall
|
|
24
|
-
|
|
25
|
-
main();
|
|
26
|
-
} catch (err) {
|
|
24
|
+
main().catch(err => {
|
|
27
25
|
console.log(` ⚠ Cleanup warning: ${err.message}`);
|
|
28
26
|
process.exit(0);
|
|
29
|
-
}
|
|
27
|
+
});
|
|
@@ -87,12 +87,13 @@ function buildUserContext() {
|
|
|
87
87
|
const packageDir = getPackageDir();
|
|
88
88
|
const iconDir = path.join(packageDir, 'assets');
|
|
89
89
|
|
|
90
|
-
// Determine where npm placed the nexora
|
|
91
|
-
const
|
|
90
|
+
// Determine where npm placed the nexora binary (reads bin name from package.json)
|
|
91
|
+
const { binName } = require('./config.cjs').getNexoraConfig();
|
|
92
|
+
const binaryName = platform === 'windows' ? `${binName}.cmd` : binName;
|
|
92
93
|
// npm puts global bins next to the node executable on Windows,
|
|
93
94
|
// or in /usr/local/bin (or prefix/bin) on Unix.
|
|
94
95
|
// process.execPath → e.g. C:\Program Files\nodejs\node.exe
|
|
95
|
-
// dirname → C:\Program Files\nodejs\ → that's where nexora
|
|
96
|
+
// dirname → C:\Program Files\nodejs\ → that's where nexora.cmd lives
|
|
96
97
|
const npmBinDir = path.dirname(process.execPath);
|
|
97
98
|
const binaryPath = path.join(npmBinDir, binaryName);
|
|
98
99
|
|
|
@@ -101,12 +102,13 @@ function buildUserContext() {
|
|
|
101
102
|
|
|
102
103
|
// ── Public API ────────────────────────────────────────────────────────────────
|
|
103
104
|
|
|
104
|
-
function createShortcut() {
|
|
105
|
+
async function createShortcut() {
|
|
105
106
|
const ctx = buildUserContext();
|
|
106
107
|
|
|
107
108
|
if (!ctx.desktopPath) {
|
|
109
|
+
const { binName } = require('./config.cjs').getNexoraConfig();
|
|
108
110
|
console.log(' ℹ No desktop found (headless / server / WSL environment).');
|
|
109
|
-
console.log(
|
|
111
|
+
console.log(` Run "${binName}" in any terminal to start.`);
|
|
110
112
|
return;
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -117,22 +119,22 @@ function createShortcut() {
|
|
|
117
119
|
console.log('');
|
|
118
120
|
|
|
119
121
|
switch (ctx.platform) {
|
|
120
|
-
case 'windows': require('./windows.cjs').createWindowsShortcut(ctx); break;
|
|
121
|
-
case 'macos': require('./macos.cjs').createMacosShortcut(ctx); break;
|
|
122
|
-
case 'linux': require('./linux.cjs').createLinuxShortcut(ctx); break;
|
|
122
|
+
case 'windows': await require('./windows.cjs').createWindowsShortcut(ctx); break;
|
|
123
|
+
case 'macos': await require('./macos.cjs').createMacosShortcut(ctx); break;
|
|
124
|
+
case 'linux': await require('./linux.cjs').createLinuxShortcut(ctx); break;
|
|
123
125
|
default:
|
|
124
126
|
console.log(' ⚠ Unrecognised platform — skipping shortcut creation.');
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
function removeShortcut() {
|
|
130
|
+
async function removeShortcut() {
|
|
129
131
|
const ctx = buildUserContext();
|
|
130
132
|
if (!ctx.desktopPath) return;
|
|
131
133
|
|
|
132
134
|
switch (ctx.platform) {
|
|
133
|
-
case 'windows': require('./windows.cjs').removeWindowsShortcut(ctx); break;
|
|
134
|
-
case 'macos': require('./macos.cjs').removeMacosShortcut(ctx); break;
|
|
135
|
-
case 'linux': require('./linux.cjs').removeLinuxShortcut(ctx); break;
|
|
135
|
+
case 'windows': await require('./windows.cjs').removeWindowsShortcut(ctx); break;
|
|
136
|
+
case 'macos': await require('./macos.cjs').removeMacosShortcut(ctx); break;
|
|
137
|
+
case 'linux': await require('./linux.cjs').removeLinuxShortcut(ctx); break;
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function getWTSettingsPath() {
|
|
7
|
+
const localAppData = process.env.LOCALAPPDATA || '';
|
|
8
|
+
const candidates = [
|
|
9
|
+
// Store version
|
|
10
|
+
path.join(localAppData, 'Packages', 'Microsoft.WindowsTerminal_8wekyb3d8bbwe', 'LocalState', 'settings.json'),
|
|
11
|
+
// Preview version
|
|
12
|
+
path.join(localAppData, 'Packages', 'Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe', 'LocalState', 'settings.json'),
|
|
13
|
+
// Winget / scoop version
|
|
14
|
+
path.join(localAppData, 'Microsoft', 'Windows Terminal', 'settings.json'),
|
|
15
|
+
];
|
|
16
|
+
return candidates.find(p => {
|
|
17
|
+
try { fs.accessSync(p); return true; } catch { return false; }
|
|
18
|
+
}) || null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { execSync } = require('child_process');
|
|
22
|
+
const { getNexoraConfig } = require('./config.cjs');
|
|
23
|
+
|
|
24
|
+
async function resolveNexoraAbsolutePath(binName) {
|
|
25
|
+
// Try where.exe with the correct command name
|
|
26
|
+
try {
|
|
27
|
+
const result = execSync(`where ${binName}`, { stdio: 'pipe' })
|
|
28
|
+
.toString().trim().split('\n')[0].trim();
|
|
29
|
+
if (result) return result;
|
|
30
|
+
} catch { /* not on PATH yet */ }
|
|
31
|
+
|
|
32
|
+
// Fallback: build from npm prefix
|
|
33
|
+
try {
|
|
34
|
+
const prefix = execSync('npm config get prefix', { stdio: 'pipe' }).toString().trim();
|
|
35
|
+
const candidate = path.join(prefix, `${binName}.cmd`);
|
|
36
|
+
fs.accessSync(candidate);
|
|
37
|
+
return candidate;
|
|
38
|
+
} catch { /* not found */ }
|
|
39
|
+
|
|
40
|
+
throw new Error(
|
|
41
|
+
`${binName}.cmd not found. ` +
|
|
42
|
+
`Ensure "npm install -g nexora-code" completed successfully.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function detectBestShell(binName) {
|
|
47
|
+
try {
|
|
48
|
+
execSync('where pwsh.exe', { stdio: 'pipe' });
|
|
49
|
+
return { shellExe: 'pwsh.exe' };
|
|
50
|
+
} catch { /* not found */ }
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
shellExe: 'powershell.exe',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function repairWTProfile() {
|
|
58
|
+
const settingsPath = getWTSettingsPath();
|
|
59
|
+
if (!settingsPath) return; // WT not installed or can't find settings
|
|
60
|
+
|
|
61
|
+
let settings;
|
|
62
|
+
try {
|
|
63
|
+
const raw = fs.readFileSync(settingsPath, 'utf-8');
|
|
64
|
+
// WT settings.json may have comments — strip them before parsing
|
|
65
|
+
const stripped = raw.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
66
|
+
settings = JSON.parse(stripped);
|
|
67
|
+
} catch {
|
|
68
|
+
return; // Can't parse — don't corrupt the file
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const profiles = settings?.profiles?.list;
|
|
72
|
+
if (!Array.isArray(profiles)) return;
|
|
73
|
+
|
|
74
|
+
let modified = false;
|
|
75
|
+
|
|
76
|
+
for (const profile of profiles) {
|
|
77
|
+
const { binName } = getNexoraConfig();
|
|
78
|
+
// Find any profile where commandline is set to bare "nexora-code" or old binName
|
|
79
|
+
if (
|
|
80
|
+
profile.name === 'Nexora Code' &&
|
|
81
|
+
(profile.commandline === 'nexora-code' || profile.commandline === binName)
|
|
82
|
+
) {
|
|
83
|
+
const { shellExe } = detectBestShell(binName);
|
|
84
|
+
const nexoraAbs = await resolveNexoraAbsolutePath(binName);
|
|
85
|
+
|
|
86
|
+
profile.commandline = `${shellExe} -NoExit -Command "& '${nexoraAbs.replace(/\\/g, '\\\\').replace(/'/g, "''")}'"`;
|
|
87
|
+
modified = true;
|
|
88
|
+
|
|
89
|
+
console.log(' ✓ Repaired corrupted Windows Terminal profile.');
|
|
90
|
+
console.log(` ✓ Fixed commandline → ${profile.commandline}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (modified) {
|
|
95
|
+
// Write back with 4-space indent to match WT's own format
|
|
96
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 4), 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = { repairWTProfile, resolveNexoraAbsolutePath };
|
|
@@ -4,93 +4,148 @@
|
|
|
4
4
|
// ║ Creates a .lnk file via PowerShell COM (WScript.Shell) — zero deps ║
|
|
5
5
|
// ╚══════════════════════════════════════════════════════════════════════════════╝
|
|
6
6
|
|
|
7
|
-
const { execSync }
|
|
8
|
-
const path
|
|
9
|
-
const fs
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
const { repairWTProfile, resolveNexoraAbsolutePath } = require('./windows-wt-profile.cjs');
|
|
13
|
+
const { getNexoraConfig } = require('./config.cjs');
|
|
14
|
+
|
|
15
|
+
// ── Terminal detection ────────────────────────────────────────────────────────
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
18
|
+
* Returns the best shell exe + base args for launching in that shell.
|
|
19
|
+
* binPath is the absolute path to nexora.cmd — passed separately so
|
|
20
|
+
* detectWindowsTerminal doesn't need to know the command name.
|
|
14
21
|
*/
|
|
15
22
|
function detectWindowsTerminal() {
|
|
16
|
-
// Windows Terminal (wt.exe) — best
|
|
23
|
+
// Windows Terminal (wt.exe) — best experience
|
|
17
24
|
try {
|
|
18
|
-
execSync('where wt.exe', { stdio: 'pipe' });
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const wtPath = execSync('where wt.exe', { stdio: 'pipe' }).toString().trim().split('\n')[0].trim();
|
|
26
|
+
if (wtPath) {
|
|
27
|
+
try {
|
|
28
|
+
execSync('where pwsh.exe', { stdio: 'pipe' });
|
|
29
|
+
return { label: 'Windows Terminal + PowerShell 7', shellExe: wtPath, innerShell: 'pwsh.exe' };
|
|
30
|
+
} catch {
|
|
31
|
+
return { label: 'Windows Terminal + PowerShell 5', shellExe: wtPath, innerShell: 'powershell.exe' };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
} catch { /* wt not found */ }
|
|
25
35
|
|
|
26
|
-
// PowerShell 7+
|
|
36
|
+
// PowerShell 7+
|
|
27
37
|
try {
|
|
28
|
-
execSync('where pwsh.exe', { stdio: 'pipe' });
|
|
29
|
-
return {
|
|
30
|
-
exe: 'pwsh.exe',
|
|
31
|
-
args: '-NoExit -Command nexora-code',
|
|
32
|
-
label: 'PowerShell 7',
|
|
33
|
-
};
|
|
38
|
+
const pwsh7 = execSync('where pwsh.exe', { stdio: 'pipe' }).toString().trim().split('\n')[0].trim();
|
|
39
|
+
if (pwsh7) return { label: 'PowerShell 7', shellExe: pwsh7, innerShell: null };
|
|
34
40
|
} catch { /* not installed */ }
|
|
35
41
|
|
|
36
|
-
// PowerShell 5
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
args: '-NoExit -Command nexora-code',
|
|
40
|
-
label: 'PowerShell 5 (built-in)',
|
|
41
|
-
};
|
|
42
|
+
// PowerShell 5 — guaranteed on Windows 10/11
|
|
43
|
+
const ps5 = path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
44
|
+
return { label: 'PowerShell 5', shellExe: ps5, innerShell: null };
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
// ── Main shortcut creator ─────────────────────────────────────────────────────
|
|
48
|
+
|
|
44
49
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
50
|
+
* Builds and executes a PowerShell script file to create the .lnk shortcut.
|
|
51
|
+
* Writing to a .ps1 temp file completely sidesteps all the -Command quoting hell.
|
|
47
52
|
*/
|
|
48
|
-
function createWindowsShortcut(ctx) {
|
|
49
|
-
|
|
53
|
+
async function createWindowsShortcut(ctx) {
|
|
54
|
+
await repairWTProfile();
|
|
55
|
+
|
|
56
|
+
const { binName, displayName, description } = getNexoraConfig();
|
|
57
|
+
|
|
58
|
+
// ── 1. Resolve the absolute path to nexora.cmd ───────────────────────────
|
|
59
|
+
let nexoraAbsPath;
|
|
60
|
+
try {
|
|
61
|
+
nexoraAbsPath = await resolveNexoraAbsolutePath(binName);
|
|
62
|
+
console.log(` ✓ Binary found at : ${nexoraAbsPath}`);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.log(` ✗ ${err.message}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── 2. Build paths ───────────────────────────────────────────────────────
|
|
69
|
+
const shortcutPath = path.join(ctx.desktopPath, `${displayName}.lnk`);
|
|
50
70
|
const iconPath = path.join(ctx.iconDir, 'icon.ico');
|
|
51
71
|
const iconExists = fs.existsSync(iconPath);
|
|
52
72
|
const terminal = detectWindowsTerminal();
|
|
53
73
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`$
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
// ── 3. Build the Arguments string ────────────────────────────────────────
|
|
75
|
+
// When using Windows Terminal, wt.exe is the TargetPath and it receives
|
|
76
|
+
// the inner shell as its first argument. When using PS directly, the
|
|
77
|
+
// TargetPath is the shell exe itself.
|
|
78
|
+
let targetExe, shortcutArgs;
|
|
79
|
+
|
|
80
|
+
if (terminal.innerShell) {
|
|
81
|
+
// Windows Terminal: wt.exe powershell.exe -NoExit -Command "& 'C:\path\nexora.cmd'"
|
|
82
|
+
targetExe = terminal.shellExe; // wt.exe
|
|
83
|
+
shortcutArgs = `${terminal.innerShell} -NoExit -Command "& '${nexoraAbsPath}'"`;
|
|
84
|
+
} else {
|
|
85
|
+
// Direct shell: powershell.exe -NoExit -Command "& 'C:\path\nexora.cmd'"
|
|
86
|
+
targetExe = terminal.shellExe;
|
|
87
|
+
shortcutArgs = `-NoExit -Command "& '${nexoraAbsPath}'"`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── 4. Write a temp .ps1 script — avoids all inline quoting issues ───────
|
|
91
|
+
// PowerShell here-string (@"..."@) lets us embed any characters safely.
|
|
92
|
+
const ps1Lines = [
|
|
93
|
+
`$ws = New-Object -ComObject WScript.Shell`,
|
|
94
|
+
`$sc = $ws.CreateShortcut(@"`,
|
|
95
|
+
shortcutPath,
|
|
96
|
+
`"@)`,
|
|
97
|
+
`$sc.TargetPath = @"`,
|
|
98
|
+
targetExe,
|
|
99
|
+
`"@`,
|
|
100
|
+
`$sc.Arguments = @"`,
|
|
101
|
+
shortcutArgs,
|
|
102
|
+
`"@`,
|
|
103
|
+
`$sc.WorkingDirectory = $env:USERPROFILE`,
|
|
104
|
+
`$sc.Description = @"`,
|
|
105
|
+
description,
|
|
106
|
+
`"@`,
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
if (iconExists) {
|
|
110
|
+
ps1Lines.push(`$sc.IconLocation = @"`, iconPath, `"@`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
ps1Lines.push(`$sc.Save()`);
|
|
114
|
+
|
|
115
|
+
const ps1Content = ps1Lines.join('\r\n') + '\r\n';
|
|
116
|
+
const ps1Path = path.join(os.tmpdir(), `nexora-shortcut-${Date.now()}.ps1`);
|
|
69
117
|
|
|
70
118
|
try {
|
|
119
|
+
fs.writeFileSync(ps1Path, ps1Content, 'utf-8');
|
|
120
|
+
|
|
71
121
|
execSync(
|
|
72
|
-
`powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -
|
|
122
|
+
`powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${ps1Path}"`,
|
|
73
123
|
{ stdio: 'pipe', timeout: 20_000 }
|
|
74
124
|
);
|
|
75
|
-
|
|
76
|
-
console.log(` ✓
|
|
77
|
-
|
|
125
|
+
|
|
126
|
+
console.log(` ✓ Desktop shortcut : ${shortcutPath}`);
|
|
127
|
+
console.log(` ✓ Terminal : ${terminal.label}`);
|
|
128
|
+
console.log(` ✓ Launches : ${binName}`);
|
|
129
|
+
if (iconExists) console.log(` ✓ Icon applied : Nexora Code logo`);
|
|
78
130
|
console.log('');
|
|
79
|
-
console.log(
|
|
131
|
+
console.log(` → Double-click "${displayName}" on your Desktop to launch!`);
|
|
80
132
|
console.log('');
|
|
81
133
|
} catch (err) {
|
|
82
134
|
throw new Error(`Windows .lnk creation failed: ${err.message}`);
|
|
135
|
+
} finally {
|
|
136
|
+
// Always clean up the temp file
|
|
137
|
+
try { fs.unlinkSync(ps1Path); } catch { /* already gone */ }
|
|
83
138
|
}
|
|
84
139
|
}
|
|
85
140
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
*/
|
|
141
|
+
// ── Shortcut removal ──────────────────────────────────────────────────────────
|
|
142
|
+
|
|
89
143
|
function removeWindowsShortcut(ctx) {
|
|
90
|
-
const
|
|
144
|
+
const { displayName } = getNexoraConfig();
|
|
145
|
+
const shortcutPath = path.join(ctx.desktopPath, `${displayName}.lnk`);
|
|
91
146
|
try {
|
|
92
147
|
fs.unlinkSync(shortcutPath);
|
|
93
|
-
console.log(
|
|
148
|
+
console.log(` ✓ Desktop shortcut removed: ${displayName}.lnk`);
|
|
94
149
|
} catch {
|
|
95
150
|
// Already removed or never existed — that's fine
|
|
96
151
|
}
|