@zenalexa/unicli 0.223.4 → 0.224.1
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/AGENTS.md +5 -5
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/dist/adapters/marxists-cn/archive.d.ts +61 -0
- package/dist/adapters/marxists-cn/archive.d.ts.map +1 -0
- package/dist/adapters/marxists-cn/archive.js +861 -0
- package/dist/adapters/marxists-cn/archive.js.map +1 -0
- package/dist/adapters/twitter/lists-extra.d.ts +17 -1
- package/dist/adapters/twitter/lists-extra.d.ts.map +1 -1
- package/dist/adapters/twitter/lists-extra.js +123 -21
- package/dist/adapters/twitter/lists-extra.js.map +1 -1
- package/dist/adapters/twitter/post.js +1 -0
- package/dist/adapters/twitter/post.js.map +1 -1
- package/dist/adapters/twitter/thread.d.ts +13 -1
- package/dist/adapters/twitter/thread.d.ts.map +1 -1
- package/dist/adapters/twitter/thread.js +76 -33
- package/dist/adapters/twitter/thread.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/architecture.d.ts +21 -0
- package/dist/commands/architecture.d.ts.map +1 -0
- package/dist/commands/architecture.js +47 -0
- package/dist/commands/architecture.js.map +1 -0
- package/dist/commands/compute.d.ts.map +1 -1
- package/dist/commands/compute.js +31 -6
- package/dist/commands/compute.js.map +1 -1
- package/dist/commands/doctor-compute.d.ts.map +1 -1
- package/dist/commands/doctor-compute.js +88 -1
- package/dist/commands/doctor-compute.js.map +1 -1
- package/dist/compute/action-execution.d.ts +30 -0
- package/dist/compute/action-execution.d.ts.map +1 -0
- package/dist/compute/action-execution.js +112 -0
- package/dist/compute/action-execution.js.map +1 -0
- package/dist/compute/capture-reference.d.ts.map +1 -1
- package/dist/compute/capture-reference.js +6 -1
- package/dist/compute/capture-reference.js.map +1 -1
- package/dist/compute/capture.d.ts +2 -0
- package/dist/compute/capture.d.ts.map +1 -1
- package/dist/compute/capture.js +6 -1
- package/dist/compute/capture.js.map +1 -1
- package/dist/compute/cursor-visual-style.d.ts +35 -0
- package/dist/compute/cursor-visual-style.d.ts.map +1 -0
- package/dist/compute/cursor-visual-style.js +39 -0
- package/dist/compute/cursor-visual-style.js.map +1 -0
- package/dist/compute/linux-overlay.d.ts +38 -0
- package/dist/compute/linux-overlay.d.ts.map +1 -0
- package/dist/compute/linux-overlay.js +274 -0
- package/dist/compute/linux-overlay.js.map +1 -0
- package/dist/compute/macos-overlay.d.ts +64 -0
- package/dist/compute/macos-overlay.d.ts.map +1 -0
- package/dist/compute/macos-overlay.js +590 -0
- package/dist/compute/macos-overlay.js.map +1 -0
- package/dist/compute/overlay-daemon.d.ts +47 -0
- package/dist/compute/overlay-daemon.d.ts.map +1 -0
- package/dist/compute/overlay-daemon.js +206 -0
- package/dist/compute/overlay-daemon.js.map +1 -0
- package/dist/compute/overlay.d.ts +42 -0
- package/dist/compute/overlay.d.ts.map +1 -0
- package/dist/compute/overlay.js +111 -0
- package/dist/compute/overlay.js.map +1 -0
- package/dist/compute/platform-overlays.d.ts +20 -0
- package/dist/compute/platform-overlays.d.ts.map +1 -0
- package/dist/compute/platform-overlays.js +31 -0
- package/dist/compute/platform-overlays.js.map +1 -0
- package/dist/compute/visual-timeline.d.ts +132 -0
- package/dist/compute/visual-timeline.d.ts.map +1 -0
- package/dist/compute/visual-timeline.js +431 -0
- package/dist/compute/visual-timeline.js.map +1 -0
- package/dist/compute/windows-overlay.d.ts +38 -0
- package/dist/compute/windows-overlay.d.ts.map +1 -0
- package/dist/compute/windows-overlay.js +282 -0
- package/dist/compute/windows-overlay.js.map +1 -0
- package/dist/core/architecture-tree.d.ts +68 -0
- package/dist/core/architecture-tree.d.ts.map +1 -0
- package/dist/core/architecture-tree.js +215 -0
- package/dist/core/architecture-tree.js.map +1 -0
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +93 -0
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/core-catalog.d.ts.map +1 -1
- package/dist/discovery/core-catalog.js +14 -0
- package/dist/discovery/core-catalog.js.map +1 -1
- package/dist/discovery/intents.d.ts.map +1 -1
- package/dist/discovery/intents.js +124 -0
- package/dist/discovery/intents.js.map +1 -1
- package/dist/discovery/loader.d.ts +12 -6
- package/dist/discovery/loader.d.ts.map +1 -1
- package/dist/discovery/loader.js +37 -10
- package/dist/discovery/loader.js.map +1 -1
- package/dist/discovery/search.d.ts +27 -28
- package/dist/discovery/search.d.ts.map +1 -1
- package/dist/discovery/search.js +118 -120
- package/dist/discovery/search.js.map +1 -1
- package/dist/engine/text-normalize.d.ts +14 -0
- package/dist/engine/text-normalize.d.ts.map +1 -1
- package/dist/engine/text-normalize.js +64 -0
- package/dist/engine/text-normalize.js.map +1 -1
- package/dist/fast-path/handlers/discovery.d.ts +12 -5
- package/dist/fast-path/handlers/discovery.d.ts.map +1 -1
- package/dist/fast-path/handlers/discovery.js +42 -7
- package/dist/fast-path/handlers/discovery.js.map +1 -1
- package/dist/manifest-compact.txt +2 -2
- package/dist/manifest.json +352 -3
- package/dist/mcp/profiles/computer-use.d.ts.map +1 -1
- package/dist/mcp/profiles/computer-use.js +76 -8
- package/dist/mcp/profiles/computer-use.js.map +1 -1
- package/dist/registry.d.ts +14 -5
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +33 -6
- package/dist/registry.js.map +1 -1
- package/dist/transport/cascade.d.ts +1 -0
- package/dist/transport/cascade.d.ts.map +1 -1
- package/dist/transport/cascade.js +2 -2
- package/dist/transport/cascade.js.map +1 -1
- package/docs/operate/compute.md +66 -1
- package/docs/operate/troubleshooting.md +42 -0
- package/package.json +9 -5
- package/server.json +3 -3
- package/skills/unicli/SKILL.md +1 -1
- package/skills/unicli-claude-code/SKILL.md +1 -1
- package/skills/unicli-hermes/SKILL.md +1 -1
- package/src/adapters/marxists-cn/archive.test.ts +173 -0
- package/src/adapters/marxists-cn/archive.ts +1049 -0
- package/src/adapters/twitter/lists-extra.test.ts +115 -0
- package/src/adapters/twitter/lists-extra.ts +146 -26
- package/src/adapters/twitter/post.ts +1 -0
- package/src/adapters/twitter/thread.test.ts +25 -1
- package/src/adapters/twitter/thread.ts +99 -47
- package/dist/manifest-search.json +0 -1
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner src/compute/macos-overlay.ts
|
|
3
|
+
* @does Render compute visual_action evidence through a macOS AppKit full-screen HUD.
|
|
4
|
+
* @needs Swift runtime, AppKit, src/compute/overlay.ts
|
|
5
|
+
* @feeds future computer-use native overlay orchestration
|
|
6
|
+
* @breaks Non-click-through or key windows can steal focus from the real action transport.
|
|
7
|
+
* @invariants The overlay is visual-only, click-through, non-key, and spans every visible screen.
|
|
8
|
+
* @side-effects launches a Swift/AppKit helper on macOS and may keep a daemon process per provider.
|
|
9
|
+
* @perf one persistent Swift process per daemon provider; one-shot provider spawns per render.
|
|
10
|
+
* @concurrency daemon provider serializes render requests; native AppKit state is process-local
|
|
11
|
+
* @test tests/unit/compute-macos-overlay-swift.test.ts
|
|
12
|
+
* @stability experimental
|
|
13
|
+
* @since 0.224.0
|
|
14
|
+
*/
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { computeOverlayRequestFromAction, } from "./overlay.js";
|
|
20
|
+
import { StdioComputeOverlayDaemonSession, } from "./overlay-daemon.js";
|
|
21
|
+
export class MacosAppKitOverlayProvider {
|
|
22
|
+
provider = "macos-appkit";
|
|
23
|
+
platform;
|
|
24
|
+
shell;
|
|
25
|
+
scriptPath;
|
|
26
|
+
lastPoint;
|
|
27
|
+
constructor(opts = {}) {
|
|
28
|
+
this.platform = opts.platform ?? process.platform;
|
|
29
|
+
this.shell = opts.shell ?? defaultShell;
|
|
30
|
+
this.scriptPath = opts.scriptPath;
|
|
31
|
+
}
|
|
32
|
+
currentPoint() {
|
|
33
|
+
return this.lastPoint;
|
|
34
|
+
}
|
|
35
|
+
async render(action) {
|
|
36
|
+
const request = computeOverlayRequestFromAction(action);
|
|
37
|
+
if (!request) {
|
|
38
|
+
return { provider: "macos-appkit", status: "not_requested" };
|
|
39
|
+
}
|
|
40
|
+
if (this.platform !== "darwin") {
|
|
41
|
+
return { provider: "macos-appkit", status: "unavailable" };
|
|
42
|
+
}
|
|
43
|
+
let tmpRoot;
|
|
44
|
+
const scriptPath = this.scriptPath ??
|
|
45
|
+
join((tmpRoot = await mkdtemp(join(tmpdir(), "unicli-overlay-"))), "main.swift");
|
|
46
|
+
try {
|
|
47
|
+
if (!this.scriptPath) {
|
|
48
|
+
await writeFile(scriptPath, buildMacosOverlaySwiftScript(), "utf8");
|
|
49
|
+
}
|
|
50
|
+
const result = await this.shell.run("swift", [scriptPath], {
|
|
51
|
+
input: JSON.stringify(request),
|
|
52
|
+
timeoutMs: Math.max(1_000, request.duration_ms + 1_500),
|
|
53
|
+
});
|
|
54
|
+
const status = parseOverlayStatus(result.stdout);
|
|
55
|
+
if (status.status === "arrived") {
|
|
56
|
+
this.lastPoint = pointFromOverlayTarget(request);
|
|
57
|
+
}
|
|
58
|
+
return status;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
provider: "macos-appkit",
|
|
63
|
+
status: "failed",
|
|
64
|
+
error: errorMessage(error),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
if (tmpRoot)
|
|
69
|
+
await rm(tmpRoot, { recursive: true, force: true });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class MacosAppKitOverlayDaemonProvider {
|
|
74
|
+
provider = "macos-appkit";
|
|
75
|
+
platform;
|
|
76
|
+
scriptPath;
|
|
77
|
+
sessionFactory;
|
|
78
|
+
session;
|
|
79
|
+
tmpRoot;
|
|
80
|
+
lastPoint;
|
|
81
|
+
constructor(opts = {}) {
|
|
82
|
+
this.platform = opts.platform ?? process.platform;
|
|
83
|
+
this.scriptPath = opts.scriptPath;
|
|
84
|
+
this.sessionFactory = opts.sessionFactory;
|
|
85
|
+
}
|
|
86
|
+
currentPoint() {
|
|
87
|
+
return this.lastPoint;
|
|
88
|
+
}
|
|
89
|
+
async render(action) {
|
|
90
|
+
const request = computeOverlayRequestFromAction(action);
|
|
91
|
+
if (!request) {
|
|
92
|
+
return { provider: "macos-appkit", status: "not_requested" };
|
|
93
|
+
}
|
|
94
|
+
if (this.platform !== "darwin") {
|
|
95
|
+
return { provider: "macos-appkit", status: "unavailable" };
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const session = await this.ensureSession();
|
|
99
|
+
const status = await session.render(request, Math.max(1_000, request.duration_ms + 1_500));
|
|
100
|
+
if (status.status === "arrived") {
|
|
101
|
+
this.lastPoint = pointFromOverlayTarget(request);
|
|
102
|
+
}
|
|
103
|
+
return status;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
provider: "macos-appkit",
|
|
108
|
+
status: "failed",
|
|
109
|
+
error: errorMessage(error),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async close() {
|
|
114
|
+
await this.session?.close();
|
|
115
|
+
this.session = undefined;
|
|
116
|
+
if (this.tmpRoot) {
|
|
117
|
+
await rm(this.tmpRoot, { recursive: true, force: true });
|
|
118
|
+
this.tmpRoot = undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async ensureSession() {
|
|
122
|
+
if (this.session)
|
|
123
|
+
return this.session;
|
|
124
|
+
if (this.sessionFactory) {
|
|
125
|
+
this.session = await this.sessionFactory();
|
|
126
|
+
return this.session;
|
|
127
|
+
}
|
|
128
|
+
const scriptPath = this.scriptPath ??
|
|
129
|
+
join((this.tmpRoot = await mkdtemp(join(tmpdir(), "unicli-overlayd-"))), "main.swift");
|
|
130
|
+
if (!this.scriptPath) {
|
|
131
|
+
await writeFile(scriptPath, buildMacosOverlayDaemonSwiftScript(), "utf8");
|
|
132
|
+
}
|
|
133
|
+
this.session = new StdioComputeOverlayDaemonSession("swift", [scriptPath]);
|
|
134
|
+
return this.session;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export function buildMacosOverlaySwiftScript() {
|
|
138
|
+
return String.raw `
|
|
139
|
+
import AppKit
|
|
140
|
+
import Foundation
|
|
141
|
+
import QuartzCore
|
|
142
|
+
|
|
143
|
+
let cursorVisualStyle = "mac-glass-pointer-v1"
|
|
144
|
+
let cursorSkin = "mac-pointer"
|
|
145
|
+
|
|
146
|
+
struct OverlaySample: Decodable {
|
|
147
|
+
let at_ms: Double
|
|
148
|
+
let x: Double
|
|
149
|
+
let y: Double
|
|
150
|
+
let screenIndex: Int?
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
struct OverlayAffordance: Decodable {
|
|
154
|
+
let cursor: String?
|
|
155
|
+
let halo: String?
|
|
156
|
+
let trail: Bool?
|
|
157
|
+
let click_ripple: Bool?
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
struct OverlayRequest: Decodable {
|
|
161
|
+
let action_id: String
|
|
162
|
+
let action: String
|
|
163
|
+
let visual_style: String?
|
|
164
|
+
let state: String?
|
|
165
|
+
let affordance: OverlayAffordance?
|
|
166
|
+
let target: OverlaySample
|
|
167
|
+
let duration_ms: Double
|
|
168
|
+
let samples: [OverlaySample]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
final class ComputeOverlayWindow: NSWindow {
|
|
172
|
+
override var canBecomeKey: Bool { false }
|
|
173
|
+
override var canBecomeMain: Bool { false }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
final class ComputeOverlayView: NSView {
|
|
177
|
+
private let haloLayer = CAShapeLayer()
|
|
178
|
+
private let stateLayer = CAShapeLayer()
|
|
179
|
+
private let coreLayer = CAShapeLayer()
|
|
180
|
+
private let trailLayer = CAShapeLayer()
|
|
181
|
+
private let screenFrame: NSRect
|
|
182
|
+
|
|
183
|
+
init(frame: NSRect, screenFrame: NSRect) {
|
|
184
|
+
self.screenFrame = screenFrame
|
|
185
|
+
super.init(frame: frame)
|
|
186
|
+
wantsLayer = true
|
|
187
|
+
layer?.backgroundColor = NSColor.clear.cgColor
|
|
188
|
+
trailLayer.fillColor = NSColor.clear.cgColor
|
|
189
|
+
trailLayer.strokeColor = NSColor(calibratedRed: 0.76, green: 0.60, blue: 0.32, alpha: 0.52).cgColor
|
|
190
|
+
trailLayer.lineWidth = 2
|
|
191
|
+
trailLayer.lineCap = .round
|
|
192
|
+
haloLayer.fillColor = NSColor(calibratedRed: 0.98, green: 0.96, blue: 0.90, alpha: 0.98).cgColor
|
|
193
|
+
haloLayer.strokeColor = NSColor(calibratedRed: 0.09, green: 0.07, blue: 0.05, alpha: 0.96).cgColor
|
|
194
|
+
haloLayer.lineWidth = 2.25
|
|
195
|
+
haloLayer.shadowColor = NSColor(calibratedWhite: 0.0, alpha: 0.45).cgColor
|
|
196
|
+
haloLayer.shadowRadius = 10
|
|
197
|
+
haloLayer.shadowOpacity = 0.72
|
|
198
|
+
haloLayer.shadowOffset = .zero
|
|
199
|
+
stateLayer.fillColor = NSColor.clear.cgColor
|
|
200
|
+
stateLayer.strokeColor = NSColor(calibratedRed: 0.76, green: 0.60, blue: 0.32, alpha: 0.78).cgColor
|
|
201
|
+
stateLayer.lineWidth = 1.5
|
|
202
|
+
stateLayer.opacity = 0
|
|
203
|
+
coreLayer.fillColor = NSColor.clear.cgColor
|
|
204
|
+
coreLayer.strokeColor = NSColor(calibratedWhite: 1.0, alpha: 0.72).cgColor
|
|
205
|
+
coreLayer.lineWidth = 1
|
|
206
|
+
layer?.addSublayer(trailLayer)
|
|
207
|
+
layer?.addSublayer(haloLayer)
|
|
208
|
+
layer?.addSublayer(stateLayer)
|
|
209
|
+
layer?.addSublayer(coreLayer)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
required init?(coder: NSCoder) { nil }
|
|
213
|
+
|
|
214
|
+
func update(point: CGPoint, trail: [CGPoint], request: OverlayRequest, elapsedMs: Double, durationMs: Double) {
|
|
215
|
+
CATransaction.begin()
|
|
216
|
+
CATransaction.setDisableActions(true)
|
|
217
|
+
let local = CGPoint(x: point.x - screenFrame.minX, y: point.y - screenFrame.minY)
|
|
218
|
+
let hotspot = local
|
|
219
|
+
let pointerPath = CGMutablePath()
|
|
220
|
+
pointerPath.move(to: local)
|
|
221
|
+
pointerPath.addLine(to: CGPoint(x: local.x, y: local.y + 45))
|
|
222
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 13, y: local.y + 32))
|
|
223
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 21, y: local.y + 55))
|
|
224
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 31, y: local.y + 51))
|
|
225
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 23, y: local.y + 29))
|
|
226
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 43, y: local.y + 29))
|
|
227
|
+
pointerPath.closeSubpath()
|
|
228
|
+
let highlightPath = CGMutablePath()
|
|
229
|
+
highlightPath.move(to: CGPoint(x: local.x + 6, y: local.y + 8))
|
|
230
|
+
highlightPath.addLine(to: CGPoint(x: local.x + 6, y: local.y + 34))
|
|
231
|
+
let trailPath = CGMutablePath()
|
|
232
|
+
for (index, global) in trail.enumerated() {
|
|
233
|
+
let p = CGPoint(x: global.x - screenFrame.minX, y: global.y - screenFrame.minY)
|
|
234
|
+
if index == 0 { trailPath.move(to: p) } else { trailPath.addLine(to: p) }
|
|
235
|
+
}
|
|
236
|
+
let state = request.state ?? ""
|
|
237
|
+
let halo = request.affordance?.halo ?? ""
|
|
238
|
+
let clickRipple = request.affordance?.click_ripple ?? false
|
|
239
|
+
let pressProgress = durationMs > 0 ? elapsedMs / durationMs : 1
|
|
240
|
+
let isPressure = (state == "press" || halo == "pressure-bloom" || clickRipple) && pressProgress >= 0.78
|
|
241
|
+
let isOrbit = state == "wait" || halo == "busy-orbit"
|
|
242
|
+
let statePath = CGMutablePath()
|
|
243
|
+
statePath.addEllipse(in: CGRect(x: local.x - 14, y: local.y - 14, width: 30, height: 30))
|
|
244
|
+
haloLayer.path = pointerPath
|
|
245
|
+
coreLayer.path = highlightPath
|
|
246
|
+
trailLayer.path = trailPath
|
|
247
|
+
stateLayer.path = statePath
|
|
248
|
+
stateLayer.opacity = isPressure || isOrbit ? 1 : 0
|
|
249
|
+
stateLayer.lineDashPattern = isOrbit ? [4 as NSNumber, 5 as NSNumber] : nil
|
|
250
|
+
CATransaction.commit()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
let data = FileHandle.standardInput.readDataToEndOfFile()
|
|
255
|
+
let request = try JSONDecoder().decode(OverlayRequest.self, from: data)
|
|
256
|
+
let displayHeight = NSScreen.screens.map { $0.frame.maxY }.max() ?? 0
|
|
257
|
+
|
|
258
|
+
func appKitPoint(_ sample: OverlaySample) -> CGPoint {
|
|
259
|
+
CGPoint(x: sample.x, y: displayHeight - sample.y)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
func sampleAt(elapsedMs: Double) -> OverlaySample {
|
|
263
|
+
guard let first = request.samples.first else { return request.target }
|
|
264
|
+
var previous = first
|
|
265
|
+
for sample in request.samples.dropFirst() {
|
|
266
|
+
if sample.at_ms >= elapsedMs {
|
|
267
|
+
let span = max(1, sample.at_ms - previous.at_ms)
|
|
268
|
+
let t = min(1, max(0, (elapsedMs - previous.at_ms) / span))
|
|
269
|
+
return OverlaySample(
|
|
270
|
+
at_ms: elapsedMs,
|
|
271
|
+
x: previous.x + (sample.x - previous.x) * t,
|
|
272
|
+
y: previous.y + (sample.y - previous.y) * t,
|
|
273
|
+
screenIndex: sample.screenIndex ?? previous.screenIndex
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
previous = sample
|
|
277
|
+
}
|
|
278
|
+
return request.target
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
let app = NSApplication.shared
|
|
282
|
+
app.setActivationPolicy(.accessory)
|
|
283
|
+
var views: [ComputeOverlayView] = []
|
|
284
|
+
for screen in NSScreen.screens {
|
|
285
|
+
let window = ComputeOverlayWindow(
|
|
286
|
+
contentRect: screen.frame,
|
|
287
|
+
styleMask: [.borderless],
|
|
288
|
+
backing: .buffered,
|
|
289
|
+
defer: false,
|
|
290
|
+
screen: screen
|
|
291
|
+
)
|
|
292
|
+
window.level = .screenSaver
|
|
293
|
+
window.backgroundColor = .clear
|
|
294
|
+
window.isOpaque = false
|
|
295
|
+
window.hasShadow = false
|
|
296
|
+
window.ignoresMouseEvents = true
|
|
297
|
+
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary]
|
|
298
|
+
let view = ComputeOverlayView(frame: NSRect(origin: .zero, size: screen.frame.size), screenFrame: screen.frame)
|
|
299
|
+
window.contentView = view
|
|
300
|
+
window.orderFrontRegardless()
|
|
301
|
+
views.append(view)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
let start = ProcessInfo.processInfo.systemUptime
|
|
305
|
+
let duration = max(120, request.duration_ms)
|
|
306
|
+
Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { timer in
|
|
307
|
+
let elapsed = (ProcessInfo.processInfo.systemUptime - start) * 1000
|
|
308
|
+
let sample = sampleAt(elapsedMs: elapsed)
|
|
309
|
+
let point = appKitPoint(sample)
|
|
310
|
+
let trail = request.samples.filter { $0.at_ms <= elapsed }.suffix(10).map(appKitPoint)
|
|
311
|
+
for view in views { view.update(point: point, trail: trail, request: request, elapsedMs: elapsed, durationMs: duration) }
|
|
312
|
+
if elapsed >= duration {
|
|
313
|
+
print("{\"provider\":\"macos-appkit\",\"status\":\"arrived\",\"acknowledged_at_ms\":\(Int(duration))}")
|
|
314
|
+
fflush(stdout)
|
|
315
|
+
timer.invalidate()
|
|
316
|
+
app.terminate(nil)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
app.run()
|
|
321
|
+
`;
|
|
322
|
+
}
|
|
323
|
+
export function buildMacosOverlayDaemonSwiftScript() {
|
|
324
|
+
return String.raw `
|
|
325
|
+
import AppKit
|
|
326
|
+
import Foundation
|
|
327
|
+
import QuartzCore
|
|
328
|
+
|
|
329
|
+
let cursorVisualStyle = "mac-glass-pointer-v1"
|
|
330
|
+
let cursorSkin = "mac-pointer"
|
|
331
|
+
|
|
332
|
+
struct OverlaySample: Decodable {
|
|
333
|
+
let at_ms: Double
|
|
334
|
+
let x: Double
|
|
335
|
+
let y: Double
|
|
336
|
+
let screenIndex: Int?
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
struct OverlayAffordance: Decodable {
|
|
340
|
+
let cursor: String?
|
|
341
|
+
let halo: String?
|
|
342
|
+
let trail: Bool?
|
|
343
|
+
let click_ripple: Bool?
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
struct OverlayRequest: Decodable {
|
|
347
|
+
let action_id: String
|
|
348
|
+
let action: String
|
|
349
|
+
let visual_style: String?
|
|
350
|
+
let state: String?
|
|
351
|
+
let affordance: OverlayAffordance?
|
|
352
|
+
let target: OverlaySample
|
|
353
|
+
let duration_ms: Double
|
|
354
|
+
let samples: [OverlaySample]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
final class ComputeOverlayWindow: NSWindow {
|
|
358
|
+
override var canBecomeKey: Bool { false }
|
|
359
|
+
override var canBecomeMain: Bool { false }
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
final class ComputeOverlayView: NSView {
|
|
363
|
+
private let haloLayer = CAShapeLayer()
|
|
364
|
+
private let stateLayer = CAShapeLayer()
|
|
365
|
+
private let coreLayer = CAShapeLayer()
|
|
366
|
+
private let trailLayer = CAShapeLayer()
|
|
367
|
+
private let screenFrame: NSRect
|
|
368
|
+
|
|
369
|
+
init(frame: NSRect, screenFrame: NSRect) {
|
|
370
|
+
self.screenFrame = screenFrame
|
|
371
|
+
super.init(frame: frame)
|
|
372
|
+
wantsLayer = true
|
|
373
|
+
layer?.backgroundColor = NSColor.clear.cgColor
|
|
374
|
+
trailLayer.fillColor = NSColor.clear.cgColor
|
|
375
|
+
trailLayer.strokeColor = NSColor(calibratedRed: 0.76, green: 0.60, blue: 0.32, alpha: 0.52).cgColor
|
|
376
|
+
trailLayer.lineWidth = 2
|
|
377
|
+
trailLayer.lineCap = .round
|
|
378
|
+
haloLayer.fillColor = NSColor(calibratedRed: 0.98, green: 0.96, blue: 0.90, alpha: 0.98).cgColor
|
|
379
|
+
haloLayer.strokeColor = NSColor(calibratedRed: 0.09, green: 0.07, blue: 0.05, alpha: 0.96).cgColor
|
|
380
|
+
haloLayer.lineWidth = 2.25
|
|
381
|
+
haloLayer.shadowColor = NSColor(calibratedWhite: 0.0, alpha: 0.45).cgColor
|
|
382
|
+
haloLayer.shadowRadius = 10
|
|
383
|
+
haloLayer.shadowOpacity = 0.72
|
|
384
|
+
haloLayer.shadowOffset = .zero
|
|
385
|
+
stateLayer.fillColor = NSColor.clear.cgColor
|
|
386
|
+
stateLayer.strokeColor = NSColor(calibratedRed: 0.76, green: 0.60, blue: 0.32, alpha: 0.78).cgColor
|
|
387
|
+
stateLayer.lineWidth = 1.5
|
|
388
|
+
stateLayer.opacity = 0
|
|
389
|
+
coreLayer.fillColor = NSColor.clear.cgColor
|
|
390
|
+
coreLayer.strokeColor = NSColor(calibratedWhite: 1.0, alpha: 0.72).cgColor
|
|
391
|
+
coreLayer.lineWidth = 1
|
|
392
|
+
layer?.addSublayer(trailLayer)
|
|
393
|
+
layer?.addSublayer(haloLayer)
|
|
394
|
+
layer?.addSublayer(stateLayer)
|
|
395
|
+
layer?.addSublayer(coreLayer)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
required init?(coder: NSCoder) { nil }
|
|
399
|
+
|
|
400
|
+
func update(point: CGPoint, trail: [CGPoint], request: OverlayRequest, elapsedMs: Double, durationMs: Double) {
|
|
401
|
+
CATransaction.begin()
|
|
402
|
+
CATransaction.setDisableActions(true)
|
|
403
|
+
let local = CGPoint(x: point.x - screenFrame.minX, y: point.y - screenFrame.minY)
|
|
404
|
+
let hotspot = local
|
|
405
|
+
let pointerPath = CGMutablePath()
|
|
406
|
+
pointerPath.move(to: local)
|
|
407
|
+
pointerPath.addLine(to: CGPoint(x: local.x, y: local.y + 45))
|
|
408
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 13, y: local.y + 32))
|
|
409
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 21, y: local.y + 55))
|
|
410
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 31, y: local.y + 51))
|
|
411
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 23, y: local.y + 29))
|
|
412
|
+
pointerPath.addLine(to: CGPoint(x: local.x + 43, y: local.y + 29))
|
|
413
|
+
pointerPath.closeSubpath()
|
|
414
|
+
let highlightPath = CGMutablePath()
|
|
415
|
+
highlightPath.move(to: CGPoint(x: local.x + 6, y: local.y + 8))
|
|
416
|
+
highlightPath.addLine(to: CGPoint(x: local.x + 6, y: local.y + 34))
|
|
417
|
+
let trailPath = CGMutablePath()
|
|
418
|
+
for (index, global) in trail.enumerated() {
|
|
419
|
+
let p = CGPoint(x: global.x - screenFrame.minX, y: global.y - screenFrame.minY)
|
|
420
|
+
if index == 0 { trailPath.move(to: p) } else { trailPath.addLine(to: p) }
|
|
421
|
+
}
|
|
422
|
+
let state = request.state ?? ""
|
|
423
|
+
let halo = request.affordance?.halo ?? ""
|
|
424
|
+
let clickRipple = request.affordance?.click_ripple ?? false
|
|
425
|
+
let pressProgress = durationMs > 0 ? elapsedMs / durationMs : 1
|
|
426
|
+
let isPressure = (state == "press" || halo == "pressure-bloom" || clickRipple) && pressProgress >= 0.78
|
|
427
|
+
let isOrbit = state == "wait" || halo == "busy-orbit"
|
|
428
|
+
let statePath = CGMutablePath()
|
|
429
|
+
statePath.addEllipse(in: CGRect(x: local.x - 14, y: local.y - 14, width: 30, height: 30))
|
|
430
|
+
haloLayer.path = pointerPath
|
|
431
|
+
coreLayer.path = highlightPath
|
|
432
|
+
trailLayer.path = trailPath
|
|
433
|
+
stateLayer.path = statePath
|
|
434
|
+
stateLayer.opacity = isPressure || isOrbit ? 1 : 0
|
|
435
|
+
stateLayer.lineDashPattern = isOrbit ? [4 as NSNumber, 5 as NSNumber] : nil
|
|
436
|
+
CATransaction.commit()
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
let app = NSApplication.shared
|
|
441
|
+
app.setActivationPolicy(.accessory)
|
|
442
|
+
let displayHeight = NSScreen.screens.map { $0.frame.maxY }.max() ?? 0
|
|
443
|
+
var views: [ComputeOverlayView] = []
|
|
444
|
+
var activeTimer: Timer?
|
|
445
|
+
|
|
446
|
+
for screen in NSScreen.screens {
|
|
447
|
+
let window = ComputeOverlayWindow(
|
|
448
|
+
contentRect: screen.frame,
|
|
449
|
+
styleMask: [.borderless],
|
|
450
|
+
backing: .buffered,
|
|
451
|
+
defer: false,
|
|
452
|
+
screen: screen
|
|
453
|
+
)
|
|
454
|
+
window.level = .screenSaver
|
|
455
|
+
window.backgroundColor = .clear
|
|
456
|
+
window.isOpaque = false
|
|
457
|
+
window.hasShadow = false
|
|
458
|
+
window.ignoresMouseEvents = true
|
|
459
|
+
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary]
|
|
460
|
+
let view = ComputeOverlayView(frame: NSRect(origin: .zero, size: screen.frame.size), screenFrame: screen.frame)
|
|
461
|
+
window.contentView = view
|
|
462
|
+
window.orderFrontRegardless()
|
|
463
|
+
views.append(view)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
print("{\"provider\":\"macos-appkit\",\"status\":\"ready\"}")
|
|
467
|
+
fflush(stdout)
|
|
468
|
+
|
|
469
|
+
func appKitPoint(_ sample: OverlaySample) -> CGPoint {
|
|
470
|
+
CGPoint(x: sample.x, y: displayHeight - sample.y)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
func sampleAt(_ request: OverlayRequest, elapsedMs: Double) -> OverlaySample {
|
|
474
|
+
guard let first = request.samples.first else { return request.target }
|
|
475
|
+
var previous = first
|
|
476
|
+
for sample in request.samples.dropFirst() {
|
|
477
|
+
if sample.at_ms >= elapsedMs {
|
|
478
|
+
let span = max(1, sample.at_ms - previous.at_ms)
|
|
479
|
+
let t = min(1, max(0, (elapsedMs - previous.at_ms) / span))
|
|
480
|
+
return OverlaySample(
|
|
481
|
+
at_ms: elapsedMs,
|
|
482
|
+
x: previous.x + (sample.x - previous.x) * t,
|
|
483
|
+
y: previous.y + (sample.y - previous.y) * t,
|
|
484
|
+
screenIndex: sample.screenIndex ?? previous.screenIndex
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
previous = sample
|
|
488
|
+
}
|
|
489
|
+
return request.target
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
func render(request: OverlayRequest) {
|
|
493
|
+
activeTimer?.invalidate()
|
|
494
|
+
let start = ProcessInfo.processInfo.systemUptime
|
|
495
|
+
let duration = max(120, request.duration_ms)
|
|
496
|
+
activeTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { timer in
|
|
497
|
+
let elapsed = (ProcessInfo.processInfo.systemUptime - start) * 1000
|
|
498
|
+
let sample = sampleAt(request, elapsedMs: elapsed)
|
|
499
|
+
let point = appKitPoint(sample)
|
|
500
|
+
let trail = request.samples.filter { $0.at_ms <= elapsed }.suffix(10).map(appKitPoint)
|
|
501
|
+
for view in views { view.update(point: point, trail: trail, request: request, elapsedMs: elapsed, durationMs: duration) }
|
|
502
|
+
if elapsed >= duration {
|
|
503
|
+
print("{\"provider\":\"macos-appkit\",\"status\":\"arrived\",\"acknowledged_at_ms\":\(Int(duration))}")
|
|
504
|
+
fflush(stdout)
|
|
505
|
+
timer.invalidate()
|
|
506
|
+
activeTimer = nil
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
512
|
+
while let line = readLine() {
|
|
513
|
+
guard let data = line.data(using: .utf8) else { continue }
|
|
514
|
+
do {
|
|
515
|
+
let request = try JSONDecoder().decode(OverlayRequest.self, from: data)
|
|
516
|
+
DispatchQueue.main.async {
|
|
517
|
+
render(request: request)
|
|
518
|
+
}
|
|
519
|
+
} catch {
|
|
520
|
+
print("{\"provider\":\"macos-appkit\",\"status\":\"failed\",\"error\":\"invalid request\"}")
|
|
521
|
+
fflush(stdout)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
DispatchQueue.main.async { app.terminate(nil) }
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
app.run()
|
|
528
|
+
`;
|
|
529
|
+
}
|
|
530
|
+
function parseOverlayStatus(stdout) {
|
|
531
|
+
try {
|
|
532
|
+
const value = JSON.parse(stdout.trim());
|
|
533
|
+
if (value.provider === "macos-appkit" && typeof value.status === "string") {
|
|
534
|
+
return value;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
// handled below
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
provider: "macos-appkit",
|
|
542
|
+
status: "failed",
|
|
543
|
+
error: "overlay sidecar returned invalid JSON",
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function pointFromOverlayTarget(request) {
|
|
547
|
+
return {
|
|
548
|
+
x: request.target.x,
|
|
549
|
+
y: request.target.y,
|
|
550
|
+
coordinate_space: {
|
|
551
|
+
kind: "screen-pixels",
|
|
552
|
+
origin: "top-left",
|
|
553
|
+
...(request.target.screenIndex !== undefined
|
|
554
|
+
? { screenIndex: request.target.screenIndex }
|
|
555
|
+
: {}),
|
|
556
|
+
},
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
function errorMessage(error) {
|
|
560
|
+
return error instanceof Error ? error.message : String(error);
|
|
561
|
+
}
|
|
562
|
+
const defaultShell = {
|
|
563
|
+
run(command, args, opts) {
|
|
564
|
+
return new Promise((resolve, reject) => {
|
|
565
|
+
const child = spawn(command, [...args], {
|
|
566
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
567
|
+
timeout: opts?.timeoutMs ?? 2_000,
|
|
568
|
+
});
|
|
569
|
+
const stdoutChunks = [];
|
|
570
|
+
const stderrChunks = [];
|
|
571
|
+
child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
|
|
572
|
+
child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
|
|
573
|
+
child.on("error", reject);
|
|
574
|
+
child.on("close", (code) => {
|
|
575
|
+
const stdout = Buffer.concat(stdoutChunks).toString("utf8");
|
|
576
|
+
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
577
|
+
if (code !== 0) {
|
|
578
|
+
reject(new Error(stderr || `${command} exited with code ${code}`));
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
resolve({ stdout, stderr });
|
|
582
|
+
});
|
|
583
|
+
if (opts?.input !== undefined) {
|
|
584
|
+
child.stdin.write(opts.input);
|
|
585
|
+
}
|
|
586
|
+
child.stdin.end();
|
|
587
|
+
});
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
//# sourceMappingURL=macos-overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos-overlay.js","sourceRoot":"","sources":["../../src/compute/macos-overlay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner src/compute/overlay-daemon.ts
|
|
3
|
+
* @does Manage JSONL stdio sessions for native compute overlay HUD daemons.
|
|
4
|
+
* @needs child_process spawn, readline, visual overlay status protocol
|
|
5
|
+
* @feeds macOS AppKit, Windows Win32, and Linux GTK overlay providers
|
|
6
|
+
* @breaks Missing ready separation causes cold-start time to consume render animation timeouts.
|
|
7
|
+
* @invariants A daemon must emit provider/status=ready before render requests are written.
|
|
8
|
+
* @side-effects Starts and kills native helper processes.
|
|
9
|
+
* @perf One persistent process per overlay provider instance.
|
|
10
|
+
* @concurrency Render calls are serialized through one active JSONL request.
|
|
11
|
+
* @test tests/unit/compute-macos-overlay-swift.test.ts
|
|
12
|
+
* @stability experimental
|
|
13
|
+
* @since 0.224.0
|
|
14
|
+
*/
|
|
15
|
+
import type { ComputeOverlayRequest } from "./overlay.js";
|
|
16
|
+
import type { ComputeVisualOverlayStatus } from "./visual-timeline.js";
|
|
17
|
+
export interface ComputeOverlayDaemonSession {
|
|
18
|
+
render(request: ComputeOverlayRequest, timeoutMs: number): Promise<ComputeVisualOverlayStatus>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare class StdioComputeOverlayDaemonSession implements ComputeOverlayDaemonSession {
|
|
22
|
+
private readonly command;
|
|
23
|
+
private readonly args;
|
|
24
|
+
private child;
|
|
25
|
+
private lines;
|
|
26
|
+
private active;
|
|
27
|
+
private readiness;
|
|
28
|
+
private readonly queue;
|
|
29
|
+
private closed;
|
|
30
|
+
private readonly readyTimeoutMs;
|
|
31
|
+
constructor(command: string, args: readonly string[], opts?: {
|
|
32
|
+
readyTimeoutMs?: number;
|
|
33
|
+
});
|
|
34
|
+
render(request: ComputeOverlayRequest, timeoutMs: number): Promise<ComputeVisualOverlayStatus>;
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
private processNext;
|
|
37
|
+
private writeActiveCall;
|
|
38
|
+
private ensureReadyChild;
|
|
39
|
+
private ensureChild;
|
|
40
|
+
private handleLine;
|
|
41
|
+
private createReadiness;
|
|
42
|
+
private resolveReadinessIfReady;
|
|
43
|
+
private rejectActive;
|
|
44
|
+
private rejectQueue;
|
|
45
|
+
private rejectReadiness;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=overlay-daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay-daemon.d.ts","sourceRoot":"","sources":["../../src/compute/overlay-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CACJ,OAAO,EAAE,qBAAqB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,qBAAa,gCAAiC,YAAW,2BAA2B;IAUhF,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAVvB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAGrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACxC,IAAI,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO;IAKxC,MAAM,CACJ,OAAO,EAAE,qBAAqB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,0BAA0B,CAAC;IAOhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,eAAe;YAcT,gBAAgB;IAO9B,OAAO,CAAC,WAAW;IA+BnB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,eAAe;CAMxB"}
|