ashtar 1.0.10

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.
@@ -0,0 +1,283 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title></title>
7
+ <style>
8
+ :root { color-scheme: dark; }
9
+ html, body {
10
+ margin: 0;
11
+ padding: 0;
12
+ background: transparent;
13
+ height: 100%;
14
+ overflow: hidden;
15
+ font: 12px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
16
+ -webkit-app-region: no-drag;
17
+ -webkit-user-select: text;
18
+ user-select: text;
19
+ pointer-events: none; /* Clicks pass through to apps behind */
20
+ }
21
+ #root {
22
+ position: fixed;
23
+ inset: 0;
24
+ padding: 32px 10px 6px 10px;
25
+ max-height: 100%;
26
+ box-sizing: border-box;
27
+ color: rgba(255, 255, 255, 0.22);
28
+ background: transparent;
29
+ border: none;
30
+ border-radius: 0;
31
+ backdrop-filter: none;
32
+ text-shadow: 0 0 1px rgba(0, 0, 0, 0.30);
33
+ white-space: pre-wrap;
34
+ word-break: break-word;
35
+ overflow-y: auto;
36
+ overflow-x: hidden;
37
+ /* Completely hide scrollbar */
38
+ scrollbar-width: none; /* Firefox */
39
+ -ms-overflow-style: none; /* IE/Edge */
40
+ cursor: text;
41
+ pointer-events: auto; /* Text area captures scroll events */
42
+ }
43
+ /* Hide scrollbar for Chromium / Electron */
44
+ #root::-webkit-scrollbar {
45
+ display: none;
46
+ width: 0;
47
+ height: 0;
48
+ }
49
+ #root.following {
50
+ cursor: grab;
51
+ outline: 1px dashed rgba(255, 255, 255, 0.10);
52
+ outline-offset: 2px;
53
+ }
54
+ @media (prefers-color-scheme: light) {
55
+ #root {
56
+ color: rgba(0, 0, 0, 0.12);
57
+ text-shadow: 0 0 1px rgba(255, 255, 255, 0.25);
58
+ }
59
+ }
60
+ #status {
61
+ position: fixed;
62
+ left: 8px;
63
+ bottom: 4px;
64
+ font-size: 10px;
65
+ color: rgba(255, 255, 255, 0.25);
66
+ text-shadow: 0 0 1px rgba(0, 0, 0, 0.3);
67
+ pointer-events: none;
68
+ transition: opacity 0.3s ease;
69
+ }
70
+ @media (prefers-color-scheme: light) {
71
+ #status {
72
+ color: rgba(0, 0, 0, 0.25);
73
+ text-shadow: 0 0 1px rgba(255, 255, 255, 0.3);
74
+ }
75
+ }
76
+ /* Brief "Copied!" flash feedback */
77
+ #copy-toast {
78
+ position: fixed;
79
+ top: 50%;
80
+ left: 50%;
81
+ transform: translate(-50%, -50%) scale(0.9);
82
+ background: rgba(255, 255, 255, 0.08);
83
+ color: rgba(255, 255, 255, 0.35);
84
+ border: 1px solid rgba(255, 255, 255, 0.08);
85
+ border-radius: 6px;
86
+ padding: 4px 14px;
87
+ font-size: 11px;
88
+ letter-spacing: 0.5px;
89
+ pointer-events: none;
90
+ opacity: 0;
91
+ transition: opacity 0.2s ease, transform 0.2s ease;
92
+ }
93
+ #copy-toast.show {
94
+ opacity: 1;
95
+ transform: translate(-50%, -50%) scale(1);
96
+ }
97
+
98
+ /* ── Question input (always visible at top) ── */
99
+ #input-bar {
100
+ display: flex;
101
+ position: fixed;
102
+ top: 6px;
103
+ left: 6px;
104
+ right: 6px;
105
+ z-index: 100;
106
+ pointer-events: auto; /* Input bar is always clickable */
107
+ }
108
+ /* input-bar is always visible via display: flex above */
109
+ #question-input {
110
+ flex: 1;
111
+ background: rgba(255, 255, 255, 0.06);
112
+ border: 1px solid rgba(255, 255, 255, 0.12);
113
+ border-radius: 4px;
114
+ color: rgba(255, 255, 255, 0.22);
115
+ font: 11px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
116
+ padding: 5px 8px;
117
+ outline: none;
118
+ caret-color: rgba(255, 255, 255, 0.30);
119
+ }
120
+ #question-input::placeholder {
121
+ color: rgba(255, 255, 255, 0.15);
122
+ }
123
+ #question-input:focus {
124
+ border-color: rgba(255, 255, 255, 0.15);
125
+ background: rgba(255, 255, 255, 0.08);
126
+ }
127
+ @media (prefers-color-scheme: light) {
128
+ #question-input {
129
+ background: rgba(0, 0, 0, 0.04);
130
+ border-color: rgba(0, 0, 0, 0.1);
131
+ color: rgba(0, 0, 0, 0.5);
132
+ caret-color: rgba(0, 0, 0, 0.3);
133
+ }
134
+ #question-input::placeholder { color: rgba(0, 0, 0, 0.15); }
135
+ #question-input:focus {
136
+ border-color: rgba(0, 0, 0, 0.2);
137
+ background: rgba(0, 0, 0, 0.06);
138
+ }
139
+ }
140
+ </style>
141
+ </head>
142
+ <body>
143
+ <div id="input-bar">
144
+ <input id="question-input" type="text" placeholder="Type question & press Enter..." autocomplete="off" spellcheck="false" />
145
+ </div>
146
+ <div id="root"></div>
147
+ <div id="status"></div>
148
+ <div id="copy-toast">Copied</div>
149
+ <script>
150
+ const { ipcRenderer } = require("electron");
151
+ const root = document.getElementById("root");
152
+ const status = document.getElementById("status");
153
+ const copyToast = document.getElementById("copy-toast");
154
+ const inputBar = document.getElementById("input-bar");
155
+ const questionInput = document.getElementById("question-input");
156
+ let statusTimer = null;
157
+ let copyToastTimer = null;
158
+
159
+ /* ── Receive text from daemon ── */
160
+ ipcRenderer.on("overlay:setText", (_e, text) => {
161
+ if (statusTimer) { clearTimeout(statusTimer); statusTimer = null; }
162
+ root.textContent = text || "";
163
+ root.scrollTop = 0;
164
+ });
165
+
166
+ ipcRenderer.on("overlay:appendStatus", (_e, text) => {
167
+ status.textContent = text || "";
168
+ if (statusTimer) clearTimeout(statusTimer);
169
+ statusTimer = setTimeout(() => { status.textContent = ""; statusTimer = null; }, 1400);
170
+ });
171
+
172
+ ipcRenderer.on("overlay:setFollowing", (_e, on) => {
173
+ root.classList.toggle("following", !!on);
174
+ });
175
+
176
+ ipcRenderer.on("overlay:scrollBy", (_e, delta) => {
177
+ root.scrollTop += delta;
178
+ });
179
+
180
+ /* ── Question input mode (for protected apps) ── */
181
+ ipcRenderer.on("overlay:showInput", () => {
182
+ inputBar.classList.add("visible");
183
+ questionInput.value = "";
184
+ questionInput.focus();
185
+ });
186
+
187
+ ipcRenderer.on("overlay:hideInput", () => {
188
+ inputBar.classList.remove("visible");
189
+ questionInput.value = "";
190
+ });
191
+
192
+ // When user clicks the input, request focus from main process
193
+ questionInput.addEventListener("mousedown", (e) => {
194
+ e.stopPropagation();
195
+ ipcRenderer.send("overlay:requestFocus");
196
+ });
197
+
198
+ // Toggle click-through when mouse enters/leaves input area
199
+ inputBar.addEventListener("mouseenter", () => {
200
+ ipcRenderer.send("overlay:enableMouse");
201
+ });
202
+ inputBar.addEventListener("mouseleave", () => {
203
+ // Only restore click-through if input is not focused
204
+ if (document.activeElement !== questionInput) {
205
+ ipcRenderer.send("overlay:disableMouse");
206
+ }
207
+ });
208
+
209
+ questionInput.addEventListener("keydown", (e) => {
210
+ if (e.key === "Enter") {
211
+ e.preventDefault();
212
+ const q = questionInput.value.trim();
213
+ if (q) {
214
+ ipcRenderer.send("overlay:questionSubmitted", q);
215
+ questionInput.value = "";
216
+ questionInput.blur();
217
+ ipcRenderer.send("overlay:disableMouse");
218
+ }
219
+ }
220
+ if (e.key === "Escape") {
221
+ questionInput.value = "";
222
+ questionInput.blur();
223
+ ipcRenderer.send("overlay:inputCancelled");
224
+ ipcRenderer.send("overlay:disableMouse");
225
+ }
226
+ // Stop propagation so hotkeys don't trigger
227
+ e.stopPropagation();
228
+ });
229
+
230
+ /* ── Copy text with Ctrl+C / Cmd+C ── */
231
+ document.addEventListener("keydown", (e) => {
232
+ if ((e.ctrlKey || e.metaKey) && e.key === "c") {
233
+ e.preventDefault();
234
+ const text = root.textContent || "";
235
+ if (!text) return;
236
+
237
+ if (navigator.clipboard && navigator.clipboard.writeText) {
238
+ navigator.clipboard.writeText(text).then(() => {
239
+ showCopyToast();
240
+ }).catch(() => {
241
+ fallbackCopy(text);
242
+ });
243
+ } else {
244
+ fallbackCopy(text);
245
+ }
246
+ }
247
+ });
248
+
249
+ function fallbackCopy(text) {
250
+ const ta = document.createElement("textarea");
251
+ ta.value = text;
252
+ ta.style.position = "fixed";
253
+ ta.style.left = "-9999px";
254
+ document.body.appendChild(ta);
255
+ ta.select();
256
+ try {
257
+ document.execCommand("copy");
258
+ showCopyToast();
259
+ } catch (err) {
260
+ // silent
261
+ }
262
+ document.body.removeChild(ta);
263
+ }
264
+
265
+ function showCopyToast() {
266
+ if (copyToastTimer) clearTimeout(copyToastTimer);
267
+ copyToast.classList.add("show");
268
+ copyToastTimer = setTimeout(() => {
269
+ copyToast.classList.remove("show");
270
+ copyToastTimer = null;
271
+ }, 800);
272
+ }
273
+
274
+ /* ── Scroll via mouse wheel even when window is unfocused ── */
275
+ document.addEventListener("wheel", (e) => {
276
+ e.preventDefault();
277
+ root.scrollTop += e.deltaY;
278
+ }, { passive: false });
279
+
280
+ root.addEventListener("scroll", () => {}, { passive: true });
281
+ </script>
282
+ </body>
283
+ </html>
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+
3
+ // desktop/src/preload.ts
4
+ var import_electron = require("electron");
5
+ import_electron.contextBridge.exposeInMainWorld("pageaiDesktop", {
6
+ version: "0.1.0"
7
+ });
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,125 @@
1
+ # capture_testpad.ps1 — Capture TestPad window using PrintWindow(PW_RENDERFULLCONTENT)
2
+ # This bypasses SetWindowDisplayAffinity completely.
3
+ param([Parameter(Mandatory=$true)][string]$OutputPath)
4
+
5
+ Add-Type -AssemblyName System.Drawing
6
+ Add-Type @"
7
+ using System;
8
+ using System.Runtime.InteropServices;
9
+ using System.Text;
10
+ using System.Drawing;
11
+ using System.Drawing.Imaging;
12
+
13
+ public class SecureCap {
14
+ public delegate bool EnumWindowsProc(IntPtr h, IntPtr l);
15
+ public delegate bool EnumChildProc(IntPtr h, IntPtr l);
16
+
17
+ [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc cb, IntPtr l);
18
+ [DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr parent, EnumChildProc cb, IntPtr l);
19
+ [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr h, StringBuilder s, int m);
20
+ [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int m);
21
+ [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
22
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
23
+ [DllImport("user32.dll")] public static extern bool GetClientRect(IntPtr h, out RECT r);
24
+ [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr hdc, uint flags);
25
+ [DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr h);
26
+ [DllImport("user32.dll")] public static extern int ReleaseDC(IntPtr h, IntPtr hdc);
27
+ [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
28
+ [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int w, int h);
29
+ [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);
30
+ [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr obj);
31
+ [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hdc);
32
+
33
+ [StructLayout(LayoutKind.Sequential)]
34
+ public struct RECT { public int Left, Top, Right, Bottom; }
35
+
36
+ // Find TestPad main window
37
+ public static IntPtr FindTestpadWindow() {
38
+ IntPtr found = IntPtr.Zero;
39
+ EnumWindows((h, l) => {
40
+ if (!IsWindowVisible(h)) return true;
41
+ var sb = new StringBuilder(512);
42
+ GetWindowText(h, sb, 512);
43
+ string title = sb.ToString().ToLower();
44
+ if (title.Contains("testpad") || title.Contains("chitkara") || title.Contains("exam") || title.Contains("assessment")) {
45
+ found = h;
46
+ return false;
47
+ }
48
+ return true;
49
+ }, IntPtr.Zero);
50
+ return found;
51
+ }
52
+
53
+ // Find the Chrome_WidgetWin_1 child (where webview content renders)
54
+ public static IntPtr FindWebViewChild(IntPtr parent) {
55
+ IntPtr found = IntPtr.Zero;
56
+ EnumChildWindows(parent, (h, l) => {
57
+ var cls = new StringBuilder(256);
58
+ GetClassName(h, cls, 256);
59
+ string cn = cls.ToString();
60
+ if (cn == "Chrome_WidgetWin_1" || cn == "Chrome_RenderWidgetHostHWND" ||
61
+ cn.Contains("WebView") || cn.Contains("Chromium")) {
62
+ RECT cr; GetClientRect(h, out cr);
63
+ if (cr.Right - cr.Left > 200 && cr.Bottom - cr.Top > 200) {
64
+ found = h;
65
+ return false;
66
+ }
67
+ }
68
+ return true;
69
+ }, IntPtr.Zero);
70
+ return found;
71
+ }
72
+
73
+ public static bool Capture(string outputPath) {
74
+ IntPtr mainWnd = FindTestpadWindow();
75
+ if (mainWnd == IntPtr.Zero) return false;
76
+
77
+ // Try to find the actual webview child window
78
+ IntPtr target = FindWebViewChild(mainWnd);
79
+ if (target == IntPtr.Zero) target = mainWnd;
80
+
81
+ // Get window dimensions
82
+ RECT rc;
83
+ GetClientRect(target, out rc);
84
+ int w = rc.Right - rc.Left;
85
+ int h = rc.Bottom - rc.Top;
86
+ if (w <= 0 || h <= 0) {
87
+ GetWindowRect(target, out rc);
88
+ w = rc.Right - rc.Left;
89
+ h = rc.Bottom - rc.Top;
90
+ }
91
+ if (w <= 100 || h <= 100) return false;
92
+
93
+ // Create compatible DC and bitmap
94
+ IntPtr hdcWin = GetDC(target);
95
+ IntPtr hdcMem = CreateCompatibleDC(hdcWin);
96
+ IntPtr hBmp = CreateCompatibleBitmap(hdcWin, w, h);
97
+ IntPtr hOld = SelectObject(hdcMem, hBmp);
98
+
99
+ // PW_RENDERFULLCONTENT = 0x02 — forces hardware-accelerated content to render
100
+ bool ok = PrintWindow(target, hdcMem, 0x02);
101
+ if (!ok) {
102
+ // Fallback without PW_RENDERFULLCONTENT
103
+ ok = PrintWindow(target, hdcMem, 0);
104
+ }
105
+
106
+ // Save bitmap
107
+ if (ok) {
108
+ using (var bmp = Bitmap.FromHbitmap(hBmp)) {
109
+ bmp.Save(outputPath, ImageFormat.Png);
110
+ }
111
+ }
112
+
113
+ // Cleanup
114
+ SelectObject(hdcMem, hOld);
115
+ DeleteObject(hBmp);
116
+ DeleteDC(hdcMem);
117
+ ReleaseDC(target, hdcWin);
118
+
119
+ return ok;
120
+ }
121
+ }
122
+ "@
123
+
124
+ $result = [SecureCap]::Capture($OutputPath)
125
+ Write-Output $result
@@ -0,0 +1,37 @@
1
+ # find_testpad.ps1 — Find ALL TestPad PIDs and their display affinity
2
+ # Returns one line per protected window: pid,affinity
3
+ Add-Type @"
4
+ using System;
5
+ using System.Runtime.InteropServices;
6
+ using System.Text;
7
+ using System.Collections.Generic;
8
+ public class TPFind {
9
+ public delegate bool EWP(IntPtr h, IntPtr l);
10
+ [DllImport("user32.dll")] public static extern bool EnumWindows(EWP cb, IntPtr l);
11
+ [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr h, StringBuilder s, int m);
12
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint p);
13
+ [DllImport("user32.dll")] public static extern bool GetWindowDisplayAffinity(IntPtr h, out uint a);
14
+ [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
15
+ public static string FindAll() {
16
+ var seen = new HashSet<uint>();
17
+ var results = new List<string>();
18
+ EnumWindows((h, l) => {
19
+ if (!IsWindowVisible(h)) return true;
20
+ var t = new StringBuilder(512);
21
+ GetWindowText(h, t, 512);
22
+ string s = t.ToString().ToLower();
23
+ if (s.Contains("testpad") || s.Contains("chitkara") || s.Contains("exam") || s.Contains("assessment")) {
24
+ uint pid; GetWindowThreadProcessId(h, out pid);
25
+ if (!seen.Contains(pid)) {
26
+ uint aff; GetWindowDisplayAffinity(h, out aff);
27
+ results.Add(pid + "," + aff);
28
+ seen.Add(pid);
29
+ }
30
+ }
31
+ return true;
32
+ }, IntPtr.Zero);
33
+ return string.Join("\n", results);
34
+ }
35
+ }
36
+ "@
37
+ [TPFind]::FindAll()
@@ -0,0 +1,43 @@
1
+ param(
2
+ [Parameter(Mandatory=$true)][int]$TargetPid,
3
+ [Parameter(Mandatory=$true)][string]$DllPath
4
+ )
5
+
6
+ Add-Type @"
7
+ using System;
8
+ using System.Runtime.InteropServices;
9
+ using System.Text;
10
+ public class DllInject {
11
+ [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(uint a, bool b, int pid);
12
+ [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr h, IntPtr a, uint s, uint t, uint p);
13
+ [DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr h, IntPtr b, byte[] buf, uint s, out int w);
14
+ [DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string n);
15
+ [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr h, string n);
16
+ [DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr h, IntPtr a, uint s, IntPtr start, IntPtr param, uint f, out uint tid);
17
+ [DllImport("kernel32.dll")] public static extern uint WaitForSingleObject(IntPtr h, uint ms);
18
+ [DllImport("kernel32.dll")] public static extern bool VirtualFreeEx(IntPtr h, IntPtr a, uint s, uint t);
19
+ [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr h);
20
+ public static bool Inject(int pid, string dllPath) {
21
+ IntPtr hProc = OpenProcess(0x1F0FFF, false, pid);
22
+ if (hProc == IntPtr.Zero) return false;
23
+ byte[] pathBytes = Encoding.Unicode.GetBytes(dllPath + "\0");
24
+ IntPtr mem = VirtualAllocEx(hProc, IntPtr.Zero, (uint)pathBytes.Length, 0x3000, 0x40);
25
+ if (mem == IntPtr.Zero) { CloseHandle(hProc); return false; }
26
+ int written;
27
+ WriteProcessMemory(hProc, mem, pathBytes, (uint)pathBytes.Length, out written);
28
+ IntPtr kernel32 = GetModuleHandle("kernel32.dll");
29
+ IntPtr loadLib = GetProcAddress(kernel32, "LoadLibraryW");
30
+ uint tid;
31
+ IntPtr hThread = CreateRemoteThread(hProc, IntPtr.Zero, 0, loadLib, mem, 0, out tid);
32
+ if (hThread == IntPtr.Zero) { VirtualFreeEx(hProc, mem, 0, 0x8000); CloseHandle(hProc); return false; }
33
+ WaitForSingleObject(hThread, 10000);
34
+ VirtualFreeEx(hProc, mem, 0, 0x8000);
35
+ CloseHandle(hThread);
36
+ CloseHandle(hProc);
37
+ return true;
38
+ }
39
+ }
40
+ "@
41
+
42
+ $result = [DllInject]::Inject($TargetPid, $DllPath)
43
+ Write-Output $result
Binary file