@skylandnpm/octopus-proxy 0.1.40 → 0.1.41

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.
@@ -12467,12 +12467,12 @@ var PlatformScreenLock = class {
12467
12467
  if (signal.aborted) throw new ScreenLockError("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u5C4F\u5E55\u89E3\u9501\u5DF2\u53D6\u6D88\u3002");
12468
12468
  };
12469
12469
  check();
12470
- if (!password || Buffer.byteLength(password) > 1024 || /[\x00-\x1f\x7f]/.test(password)) throw new ScreenLockError("\u4E3B\u673A\u5BC6\u7801\u683C\u5F0F\u65E0\u6548\u3002");
12471
- if (Date.now() < this.blockedUntil) throw new ScreenLockError("\u5BC6\u7801\u9A8C\u8BC1\u5931\u8D25\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\u3002");
12472
12470
  const status = await this.status();
12473
12471
  check();
12474
12472
  if (!status.locked) return status;
12475
12473
  if (!status.canUnlock) throw new ScreenLockError(status.message ?? "\u4E3B\u673A\u4E0D\u652F\u6301\u5C4F\u5E55\u89E3\u9501\u3002");
12474
+ if (!password || Buffer.byteLength(password) > 1024 || /[\x00-\x1f\x7f]/.test(password)) throw new ScreenLockError("\u4E3B\u673A\u5BC6\u7801\u683C\u5F0F\u65E0\u6548\u3002");
12475
+ if (Date.now() < this.blockedUntil) throw new ScreenLockError("\u5BC6\u7801\u9A8C\u8BC1\u5931\u8D25\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\u3002");
12476
12476
  let valid;
12477
12477
  try {
12478
12478
  valid = await this.authenticate(this.stateDirectory, this.account.username, password);
@@ -12489,6 +12489,10 @@ var PlatformScreenLock = class {
12489
12489
  }
12490
12490
  this.failures = 0;
12491
12491
  if (this.system === "darwin") {
12492
+ const current = await this.status();
12493
+ check();
12494
+ if (!current.locked) return current;
12495
+ if (!current.canUnlock) throw new ScreenLockError(current.message ?? "\u4E3B\u673A\u4E0D\u652F\u6301\u5C4F\u5E55\u89E3\u9501\u3002");
12492
12496
  const helper = await this.macHelper();
12493
12497
  check();
12494
12498
  const bytes = Buffer.from(password, "utf8"), input = Buffer.alloc(bytes.length + 2);
@@ -12507,7 +12511,8 @@ var PlatformScreenLock = class {
12507
12511
  }
12508
12512
  const session = await this.linuxSession(signal);
12509
12513
  check();
12510
- if (session.locked) await this.execute("loginctl", ["--no-ask-password", "unlock-session", session.id], void 0, signal);
12514
+ if (!session.locked) return { ...status, locked: false };
12515
+ await this.execute("loginctl", ["--no-ask-password", "unlock-session", session.id], void 0, signal);
12511
12516
  for (let i = 0; i < 20; i++) {
12512
12517
  check();
12513
12518
  const current = await this.linuxSession(signal);
package/dist/cli.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  runDaemon,
29
29
  supportedPlatform,
30
30
  systemdUnitPath
31
- } from "./chunk-OXA2S7UY.js";
31
+ } from "./chunk-WSL4LYYW.js";
32
32
 
33
33
  // src/cli.ts
34
34
  import { spawn as spawn2 } from "node:child_process";
package/dist/main.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConfigError,
4
4
  runDaemon
5
- } from "./chunk-OXA2S7UY.js";
5
+ } from "./chunk-WSL4LYYW.js";
6
6
 
7
7
  // src/main.ts
8
8
  runDaemon(process.env.OCTOPUS_PROXY_CONFIG ?? "proxy.json").catch((error) => {
@@ -29,6 +29,39 @@ static NSDictionary *displayInfo(CGDirectDisplayID displayId) {
29
29
  @"width": @(CGDisplayPixelsWide(displayId)), @"height": @(CGDisplayPixelsHigh(displayId))};
30
30
  }
31
31
 
32
+ static BOOL saveImage(CGImageRef image, NSString *path) {
33
+ if (!image) return NO;
34
+ CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:path], CFSTR("public.png"), 1, NULL);
35
+ if (!destination) return NO;
36
+ CGImageDestinationAddImage(destination, image, NULL);
37
+ BOOL saved = CGImageDestinationFinalize(destination);
38
+ CFRelease(destination);
39
+ return saved;
40
+ }
41
+
42
+ static void finishImage(BOOL saved) {
43
+ dispatch_async(dispatch_get_main_queue(), ^{
44
+ if (finished) return;
45
+ if (saved) { resultCode = 0; finished = YES; }
46
+ else fail(@"无法保存桌面 PNG 截图,请检查 Proxy 状态目录。" );
47
+ });
48
+ }
49
+
50
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 140000
51
+ static void captureImage(SCContentFilter *filter, SCStreamConfiguration *configuration, NSString *path) API_AVAILABLE(macos(14.0));
52
+ static void captureImage(SCContentFilter *filter, SCStreamConfiguration *configuration, NSString *path) {
53
+ // A stream may start successfully without delivering frames while the screen
54
+ // is locked. The screenshot API completes a single capture without that wait.
55
+ [SCScreenshotManager captureImageWithFilter:filter configuration:configuration completionHandler:^(CGImageRef image, NSError *error) {
56
+ if (error || !image) {
57
+ dispatch_async(dispatch_get_main_queue(), ^{ if (!finished) fail(permissionMessage()); });
58
+ return;
59
+ }
60
+ finishImage(saveImage(image, path));
61
+ }];
62
+ }
63
+ #endif
64
+
32
65
  @interface DesktopFrame : NSObject <SCStreamOutput, SCStreamDelegate>
33
66
  @property(nonatomic, strong) SCStream *stream;
34
67
  @property(nonatomic, copy) NSString *path;
@@ -49,23 +82,11 @@ static NSDictionary *displayInfo(CGDirectDisplayID displayId) {
49
82
  self.received = YES;
50
83
  CGImageRef image = NULL;
51
84
  OSStatus conversion = VTCreateCGImageFromCVPixelBuffer(pixel, NULL, &image);
52
- BOOL saved = NO;
53
- if (conversion == noErr && image) {
54
- CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:self.path], CFSTR("public.png"), 1, NULL);
55
- if (destination) {
56
- CGImageDestinationAddImage(destination, image, NULL);
57
- saved = CGImageDestinationFinalize(destination);
58
- CFRelease(destination);
59
- }
60
- CGImageRelease(image);
61
- }
62
- [stream stopCaptureWithCompletionHandler:^(NSError *error) {
63
- dispatch_async(dispatch_get_main_queue(), ^{
64
- if (finished) return;
65
- if (saved) { resultCode = 0; finished = YES; }
66
- else fail(@"无法保存桌面 PNG 截图,请检查 Proxy 状态目录。" );
67
- });
68
- }];
85
+ BOOL saved = conversion == noErr && saveImage(image, self.path);
86
+ if (image) CGImageRelease(image);
87
+ // Stopping a stream is cleanup; a saved PNG must not depend on its callback.
88
+ [stream stopCaptureWithCompletionHandler:nil];
89
+ finishImage(saved);
69
90
  }
70
91
  @end
71
92
 
@@ -121,6 +142,12 @@ int main(int argc, const char *argv[]) {
121
142
  configuration.showsCursor = YES;
122
143
  configuration.queueDepth = 3;
123
144
  configuration.minimumFrameInterval = CMTimeMake(1, 30);
145
+ #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 140000
146
+ if (@available(macOS 14.0, *)) {
147
+ captureImage(filter, configuration, frame.path);
148
+ return;
149
+ }
150
+ #endif
124
151
  frame.stream = [[SCStream alloc] initWithFilter:filter configuration:configuration delegate:frame];
125
152
  NSError *outputError = nil;
126
153
  if (![frame.stream addStreamOutput:frame type:SCStreamOutputTypeScreen sampleHandlerQueue:dispatch_queue_create("octopus.desktop.frame", DISPATCH_QUEUE_SERIAL) error:&outputError]) {
@@ -63,25 +63,22 @@ static BOOL key(CGKeyCode code, CGEventFlags flags, const UniChar *text, size_t
63
63
  if (!down || !up) { if (down) CFRelease(down); if (up) CFRelease(up); return NO; }
64
64
  CGEventSetFlags(down, flags); CGEventSetFlags(up, flags);
65
65
  if (text) { CGEventKeyboardSetUnicodeString(down, length, text); CGEventKeyboardSetUnicodeString(up, length, text); }
66
- CGEventPost(kCGHIDEventTap, down); CGEventPost(kCGHIDEventTap, up);
66
+ CGEventPost(kCGHIDEventTap, down);
67
+ usleep(50000);
68
+ CGEventPost(kCGHIDEventTap, up);
67
69
  CFRelease(down); CFRelease(up);
68
- usleep(20000);
70
+ usleep(50000);
69
71
  return YES;
70
72
  }
71
73
 
72
- // The locked console owns keyboard input. Space reveals the password prompt,
73
- // and Backspace removes that Space if the field was already visible. Do not
74
- // depend on loginwindow exposing an Accessibility tree (some versions do not).
74
+ // Space reveals and focuses the locked console's password prompt. Allow the
75
+ // transition to finish before typing; no Accessibility discovery is required.
75
76
  static BOOL wakePasswordPrompt(void) {
76
- const CGKeyCode keys[] = {56, 49, 51};
77
- const useconds_t settle[] = {1000000, 500000, 200000};
78
- for (int i = 0; i < 3; i++) {
79
- BOOL locked = NO;
80
- if (!lockState(&locked)) return NO;
81
- if (!locked) return YES;
82
- if (!key(keys[i], 0, NULL, 0)) return NO;
83
- usleep(settle[i]);
84
- }
77
+ BOOL locked = NO;
78
+ if (!lockState(&locked)) return NO;
79
+ if (!locked) return YES;
80
+ if (!key(49, 0, NULL, 0)) return NO;
81
+ usleep(1000000);
85
82
  return YES;
86
83
  }
87
84
 
@@ -92,7 +89,7 @@ static BOOL lockedKey(CGKeyCode code, CGEventFlags flags, const UniChar *text, s
92
89
 
93
90
  static void printDiagnostics(BOOL locked) {
94
91
  // Read-only; no wake, focus, field contents, screenshots, or input events.
95
- printf("{\"locked\":%s,\"canUnlock\":%s,\"loginwindowFound\":%s,\"inputMethod\":\"space-backspace\"}",
92
+ printf("{\"locked\":%s,\"canUnlock\":%s,\"loginwindowFound\":%s,\"inputMethod\":\"space-password\"}",
96
93
  locked ? "true" : "false", AXIsProcessTrusted() && CGPreflightPostEventAccess() ? "true" : "false",
97
94
  loginWindowPID() ? "true" : "false");
98
95
  }
@@ -118,8 +115,6 @@ int main(int argc, const char *argv[]) {
118
115
  if (!lockState(&locked)) return fail("session");
119
116
  // Saver dismissal, Touch ID or a manual unlock may finish during wake.
120
117
  if (!locked) { printStatus(NO); return 0; }
121
- if (!lockedKey(0, kCGEventFlagMaskCommand, NULL, 0) ||
122
- !lockedKey(51, 0, NULL, 0)) return fail("changed");
123
118
  UniChar characters[1024] = {0};
124
119
  NSUInteger length = password.length;
125
120
  if (length > 1024) return fail("password");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skylandnpm/octopus-proxy",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "type": "module",
5
5
  "description": "Octopus host proxy: OpenCode, Codex, ZCode and Pi adapters with service installer CLI",
6
6
  "bin": {