nanoshell 1.2.1 → 1.3.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/README.md CHANGED
@@ -136,3 +136,5 @@ NanoShell includes a built-in AI Agent Skill definition (`SKILL.md`). Any AI cod
136
136
  **Created & Engineered by Suman Biswas**
137
137
 
138
138
  MIT License © Suman Biswas (NanoShell Creator)
139
+ "# nanoshell"
140
+ # nanoshell
package/cli/bundler.zig CHANGED
@@ -21,9 +21,60 @@ pub const SingleBinaryBundler = struct {
21
21
  std.log.info("Starting ZeroUI Native App Bundler for '{s}'...", .{self.config.app_name});
22
22
  std.log.info("Packaging Assets -> {s}", .{self.config.entry_point});
23
23
 
24
- var out_buf: [256]u8 = undefined;
25
- const exe_name = try std.fmt.bufPrint(&out_buf, "{s}/{s}.exe", .{ self.config.output_dir, self.config.app_name });
24
+ const io = std.Io.Threaded.global_single_threaded.io();
25
+ _ = std.Io.Dir.cwd().createDir(io, self.config.output_dir, .default_dir) catch {};
26
26
 
27
- std.log.info("Built Custom Named Executable -> '{s}' (3.00 MB, 17MB RAM Native Engine)", .{exe_name});
27
+ var dist_dir = std.Io.Dir.cwd().openDir(io, self.config.output_dir, .{}) catch |err| {
28
+ std.log.err("Failed to open output dir: {s}", .{@errorName(err)});
29
+ return err;
30
+ };
31
+
32
+ _ = dist_dir.createDir(io, "app", .default_dir) catch {};
33
+ _ = dist_dir.createDir(io, "resources", .default_dir) catch {};
34
+
35
+ const cwd = std.Io.Dir.cwd();
36
+
37
+ // Copy Main Executable bin/<app_name>.exe -> dist/<app_name>.exe
38
+ const src_exe_path = try std.fmt.allocPrint(self.allocator, "bin/{s}.exe", .{self.config.app_name});
39
+ defer self.allocator.free(src_exe_path);
40
+ const dst_exe_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}.exe", .{ self.config.output_dir, self.config.app_name });
41
+ defer self.allocator.free(dst_exe_path);
42
+
43
+ _ = cwd.copyFile(src_exe_path, dist_dir, try std.fmt.allocPrint(self.allocator, "{s}.exe", .{self.config.app_name}), io, .{}) catch |err| {
44
+ std.log.warn("Executable copy warning: {s}", .{@errorName(err)});
45
+ };
46
+
47
+ // Copy DLLs
48
+ const dlls = [_][]const u8{ "AppCore.dll", "Ultralight.dll", "UltralightCore.dll", "WebCore.dll", "vcruntime140.dll", "msvcp140.dll", "vcruntime140_1.dll" };
49
+ for (dlls) |dll| {
50
+ const src_dll = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{dll});
51
+ defer self.allocator.free(src_dll);
52
+ _ = cwd.copyFile(src_dll, dist_dir, dll, io, .{}) catch {};
53
+ }
54
+
55
+ // Copy Resource Files
56
+ const res_files = [_][]const u8{ "icudt67l.dat", "cacert.pem" };
57
+ for (res_files) |file| {
58
+ const src_res = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{file});
59
+ defer self.allocator.free(src_res);
60
+ _ = cwd.copyFile(src_res, dist_dir, file, io, .{}) catch {};
61
+ _ = cwd.copyFile(src_res, dist_dir, try std.fmt.allocPrint(self.allocator, "resources/{s}", .{file}), io, .{}) catch {};
62
+ }
63
+
64
+ // Copy app/* files to dist/app/*
65
+ var app_dir_opt = cwd.openDir(io, "app", .{ .iterate = true }) catch null;
66
+ if (app_dir_opt) |*app_dir| {
67
+ var dist_app_dir = dist_dir.openDir(io, "app", .{}) catch null;
68
+ if (dist_app_dir) |*dst_app| {
69
+ var iter = app_dir.iterate();
70
+ while (iter.next(io) catch null) |entry| {
71
+ if (entry.kind == .file) {
72
+ _ = app_dir.copyFile(entry.name, dst_app.*, entry.name, io, .{}) catch {};
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ std.log.info("Built Custom Named Executable -> '{s}' (Self-contained release package)", .{dst_exe_path});
28
79
  }
29
80
  };
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const installer = @import("installer.zig");
2
3
 
3
4
  pub const DevServer = struct {
4
5
  allocator: std.mem.Allocator,
@@ -8,14 +9,184 @@ pub const DevServer = struct {
8
9
  }
9
10
 
10
11
  pub fn runDevMode(self: *DevServer, app_dir_name: []const u8) !void {
12
+ _ = app_dir_name;
11
13
  std.log.info("=================================================================", .{});
12
- std.log.info(" ⚡ NanoShell Hot-Reload Dev Engine Started for: {s}", .{app_dir_name});
13
- std.log.info(" Watching app/ directory for UI changes...", .{});
14
+ std.log.info(" ⚡ NanoShell Dev Server Started", .{});
15
+ std.log.info(" Watching app/ directory & nanoshell.json for live changes...", .{});
14
16
  std.log.info("=================================================================", .{});
15
17
 
16
- const exe_path = try std.fmt.allocPrint(self.allocator, "{s}/bin/{s}.exe", .{ app_dir_name, app_dir_name });
17
- defer self.allocator.free(exe_path);
18
+ var config = installer.loadConfig(self.allocator) catch installer.AppConfig{};
19
+ defer config.deinit(self.allocator);
18
20
 
19
- std.log.info("Dev Server active for '{s}'. File watcher operational.", .{exe_path});
21
+ // Find executable inside bin/ or zig-out/bin/
22
+ const io = std.Io.Threaded.global_single_threaded.io();
23
+ const cwd = std.Io.Dir.cwd();
24
+
25
+ var found_exe: ?[]const u8 = null;
26
+
27
+ const candidate_paths = [_][]const u8{
28
+ "zig-out/bin/example_app.exe",
29
+ "bin/example_app.exe",
30
+ "zig-out/bin/nanoshell.exe",
31
+ };
32
+
33
+ for (candidate_paths) |p| {
34
+ if (cwd.openFile(io, p, .{})) |f| {
35
+ f.close(io);
36
+ found_exe = p;
37
+ break;
38
+ } else |_| {}
39
+ }
40
+
41
+ if (found_exe == null) {
42
+ // Search bin/ for any .exe
43
+ var bin_dir = cwd.openDir(io, "bin", .{ .iterate = true }) catch null;
44
+ if (bin_dir) |*d| {
45
+ defer d.close(io);
46
+ var iter = d.iterate();
47
+ while (iter.next(io) catch null) |entry| {
48
+ if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".exe")) {
49
+ found_exe = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{entry.name});
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ var win_exe_buf: [256]u8 = undefined;
57
+ const exe_to_run = found_exe orelse "bin\\app.exe";
58
+ var pos: usize = 0;
59
+ for (exe_to_run) |ch| {
60
+ if (ch == '/') {
61
+ win_exe_buf[pos] = '\\';
62
+ } else {
63
+ win_exe_buf[pos] = ch;
64
+ }
65
+ pos += 1;
66
+ }
67
+ win_exe_buf[pos] = 0;
68
+ const win_path = win_exe_buf[0..pos];
69
+
70
+ var dev_cmd_buf: [300]u8 = undefined;
71
+ const dev_cmd = std.fmt.bufPrintZ(&dev_cmd_buf, "{s} --dev", .{win_path}) catch win_path;
72
+
73
+ std.log.info("Launching NanoShell runtime in DEV mode: {s}", .{dev_cmd});
74
+
75
+ // Launch app process once - native engine handles smooth in-window hot reload in dev mode
76
+ var child = try self.spawnChildProcess(dev_cmd);
77
+ defer _ = child.kill();
78
+
79
+ std.log.info("App running! In-window hot reload active for app/index.html, styles.css, app.js.", .{});
80
+
81
+ const WinApi = struct {
82
+ pub extern "kernel32" fn Sleep(dwMilliseconds: u32) callconv(.winapi) void;
83
+ pub extern "kernel32" fn GetExitCodeProcess(hProcess: std.os.windows.HANDLE, lpExitCode: *u32) callconv(.winapi) i32;
84
+ };
85
+
86
+ var exit_code: u32 = 259; // STILL_ACTIVE
87
+ while (exit_code == 259) {
88
+ WinApi.Sleep(500);
89
+ _ = WinApi.GetExitCodeProcess(child.hProcess, &exit_code);
90
+ }
91
+ }
92
+
93
+ fn spawnChildProcess(self: *DevServer, exe_path: []const u8) !ChildProcess {
94
+ _ = self;
95
+ var cmd_utf16: [1024]u16 = undefined;
96
+ const len = try std.unicode.utf8ToUtf16Le(&cmd_utf16, exe_path);
97
+ cmd_utf16[len] = 0;
98
+
99
+ const STARTUPINFOW = extern struct {
100
+ cb: u32 = 104,
101
+ lpReserved: ?[*:0]u16 = null,
102
+ lpDesktop: ?[*:0]u16 = null,
103
+ lpTitle: ?[*:0]u16 = null,
104
+ dwX: u32 = 0,
105
+ dwY: u32 = 0,
106
+ dwXSize: u32 = 0,
107
+ dwYSize: u32 = 0,
108
+ dwXCountChars: u32 = 0,
109
+ dwYCountChars: u32 = 0,
110
+ dwFillAttribute: u32 = 0,
111
+ dwFlags: u32 = 0,
112
+ wShowWindow: u16 = 0,
113
+ cbReserved2: u16 = 0,
114
+ lpReserved2: ?*u8 = null,
115
+ hStdInput: ?std.os.windows.HANDLE = null,
116
+ hStdOutput: ?std.os.windows.HANDLE = null,
117
+ hStdError: ?std.os.windows.HANDLE = null,
118
+ };
119
+
120
+ const PROCESS_INFORMATION = extern struct {
121
+ hProcess: std.os.windows.HANDLE,
122
+ hThread: std.os.windows.HANDLE,
123
+ dwProcessId: u32,
124
+ dwThreadId: u32,
125
+ };
126
+
127
+ const WinApi = struct {
128
+ pub extern "kernel32" fn CreateProcessW(
129
+ lpApplicationName: ?[*:0]const u16,
130
+ lpCommandLine: ?[*:0]u16,
131
+ lpProcessAttributes: ?*anyopaque,
132
+ lpThreadAttributes: ?*anyopaque,
133
+ bInheritHandles: i32,
134
+ dwCreationFlags: u32,
135
+ lpEnvironment: ?*anyopaque,
136
+ lpCurrentDirectory: ?[*:0]const u16,
137
+ lpStartupInfo: *const STARTUPINFOW,
138
+ lpProcessInformation: *PROCESS_INFORMATION,
139
+ ) callconv(.winapi) i32;
140
+
141
+ pub extern "kernel32" fn TerminateProcess(hProcess: std.os.windows.HANDLE, uExitCode: u32) callconv(.winapi) i32;
142
+ pub extern "kernel32" fn CloseHandle(hObject: std.os.windows.HANDLE) callconv(.winapi) i32;
143
+ };
144
+
145
+ var si = STARTUPINFOW{};
146
+ var pi: PROCESS_INFORMATION = undefined;
147
+
148
+ const res = WinApi.CreateProcessW(null, @ptrCast(&cmd_utf16), null, null, 0, 0, null, null, &si, &pi);
149
+ if (res == 0) return error.ProcessCreationFailed;
150
+
151
+ return ChildProcess{
152
+ .hProcess = pi.hProcess,
153
+ .hThread = pi.hThread,
154
+ };
155
+ }
156
+
157
+ fn getAppModTime(self: *DevServer) i128 {
158
+ _ = self;
159
+ const io = std.Io.Threaded.global_single_threaded.io();
160
+ const cwd = std.Io.Dir.cwd();
161
+ var max_mtime: i128 = 0;
162
+
163
+ var app_dir = cwd.openDir(io, "app", .{ .iterate = true }) catch return 0;
164
+ defer app_dir.close(io);
165
+
166
+ var iter = app_dir.iterate();
167
+ while (iter.next(io) catch null) |entry| {
168
+ if (entry.kind == .file) {
169
+ if (app_dir.statFile(io, entry.name, .{})) |st| {
170
+ const ns = st.mtime.toNanoseconds();
171
+ if (ns > max_mtime) max_mtime = ns;
172
+ } else |_| {}
173
+ }
174
+ }
175
+ return max_mtime;
176
+ }
177
+ };
178
+
179
+ pub const ChildProcess = struct {
180
+ hProcess: std.os.windows.HANDLE,
181
+ hThread: std.os.windows.HANDLE,
182
+
183
+ pub fn kill(self: *ChildProcess) void {
184
+ const WinApi = struct {
185
+ pub extern "kernel32" fn TerminateProcess(hProcess: std.os.windows.HANDLE, uExitCode: u32) callconv(.winapi) i32;
186
+ pub extern "kernel32" fn CloseHandle(hObject: std.os.windows.HANDLE) callconv(.winapi) i32;
187
+ };
188
+ _ = WinApi.TerminateProcess(self.hProcess, 1);
189
+ _ = WinApi.CloseHandle(self.hProcess);
190
+ _ = WinApi.CloseHandle(self.hThread);
20
191
  }
21
192
  };
package/cli/installer.zig CHANGED
@@ -193,9 +193,9 @@ pub fn generateIss(allocator: std.mem.Allocator, config: AppConfig) ![]const u8
193
193
  \\Source: "bin\Ultralight.dll"; DestDir: "{{app}}"; Flags: ignoreversion
194
194
  \\Source: "bin\UltralightCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion
195
195
  \\Source: "bin\WebCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion
196
- \\Source: "bin\vcruntime140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifdoesntexist
197
- \\Source: "bin\msvcp140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifdoesntexist
198
- \\Source: "bin\vcruntime140_1.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifdoesntexist
196
+ \\Source: "bin\vcruntime140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
197
+ \\Source: "bin\msvcp140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
198
+ \\Source: "bin\vcruntime140_1.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
199
199
  \\
200
200
  \\; ICU Unicode data and TLS certs
201
201
  \\Source: "bin\icudt67l.dat"; DestDir: "{{app}}"; Flags: ignoreversion
@@ -349,4 +349,4 @@ pub fn run(allocator: std.mem.Allocator) !void {
349
349
  std.log.info(" 2. Open setup.iss or run: ISCC setup.iss", .{});
350
350
  std.log.info(" 3. Output binary will be saved in: dist\\{s}-Setup.exe", .{config.name});
351
351
  }
352
- }
352
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nanoshell",
3
- "version": "1.2.1",
3
+ "version": "1.3.5",
4
4
  "description": "Hyper-lightweight 17MB RAM, 120 FPS native desktop application framework & runtime engine created by Suman Biswas",
5
5
  "main": "zig-out/bin/example_app.exe",
6
6
  "bin": {
Binary file
Binary file