opencrater 0.2.5 → 1.0.0
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/LICENSE +38 -216
- package/README.md +105 -40
- package/dist/cli.js +19 -0
- package/dist/dismiss.js +3 -0
- package/dist/hook.js +6 -0
- package/dist/index.d.mts +209 -0
- package/dist/index.d.ts +209 -0
- package/dist/index.js +6 -0
- package/dist/index.mjs +6 -0
- package/dist/paint.js +9 -0
- package/package.json +35 -13
- package/cli.js +0 -416
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/** Host environment the SDK is running inside. */
|
|
2
|
+
type Host = "claude_code" | "codex" | "openclaw" | "gemini_cli" | "copilot_cli" | "generic";
|
|
3
|
+
/** Creative formats the serve API can return. Text always renders; rich
|
|
4
|
+
* media degrades to the text fallback when the terminal can't display it. */
|
|
5
|
+
type CreativeFormat = "text" | "logo" | "image" | "gif" | "video" | "audio";
|
|
6
|
+
/** Creative payload. `mediaUrl`/`textFallback` accompany non-text formats. */
|
|
7
|
+
interface Creative {
|
|
8
|
+
format: CreativeFormat;
|
|
9
|
+
title: string;
|
|
10
|
+
body: string;
|
|
11
|
+
cta?: string;
|
|
12
|
+
/** Hosted asset URL for image/gif/video/audio creatives. */
|
|
13
|
+
mediaUrl?: string;
|
|
14
|
+
/** pixel-art variant authored at the terminal grid (painter fast path) */
|
|
15
|
+
mediaPixelUrl?: string;
|
|
16
|
+
/** optional audio track that plays when the card renders (any format) */
|
|
17
|
+
audioUrl?: string;
|
|
18
|
+
/** Upload-time text fallback rendered when rich media can't display. */
|
|
19
|
+
textFallback?: string;
|
|
20
|
+
}
|
|
21
|
+
/** A served sponsor ad. `clickUrl` is the per-impression tracked redirect. */
|
|
22
|
+
interface Ad {
|
|
23
|
+
impressionId: string;
|
|
24
|
+
/** Campaign identity — used for LOCAL politeness (dismiss cooldown). */
|
|
25
|
+
campaignId?: string;
|
|
26
|
+
clickUrl: string;
|
|
27
|
+
sponsorLabel: string;
|
|
28
|
+
creative: Creative;
|
|
29
|
+
}
|
|
30
|
+
/** Publisher funding fallback rendered when no campaign fills. */
|
|
31
|
+
interface Fallback {
|
|
32
|
+
title: string;
|
|
33
|
+
body: string;
|
|
34
|
+
url: string;
|
|
35
|
+
}
|
|
36
|
+
/** Server-controlled SDK config (cached locally between fetches). */
|
|
37
|
+
interface RemoteConfig {
|
|
38
|
+
minIntervalSeconds: number;
|
|
39
|
+
serveTimeoutMs: number;
|
|
40
|
+
preloadPoolSize: number;
|
|
41
|
+
killSwitch: boolean;
|
|
42
|
+
/** How long a painted card stays on screen, in seconds (admin-tunable). */
|
|
43
|
+
displayDurationSeconds: number;
|
|
44
|
+
/** Minimum SDK version the platform wants running. A runtime below this
|
|
45
|
+
* force-updates immediately (bypassing the daily cycle) — the lever to push
|
|
46
|
+
* a critical fix without waiting. Empty = no floor. */
|
|
47
|
+
minSdkVersion: string;
|
|
48
|
+
}
|
|
49
|
+
/** Response of POST /v1/serve. */
|
|
50
|
+
interface ServeResponse {
|
|
51
|
+
fill: boolean;
|
|
52
|
+
ad?: Ad;
|
|
53
|
+
fallback?: Fallback | null;
|
|
54
|
+
config: RemoteConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Hooks the package owner selected for this host. The SDK registers every
|
|
57
|
+
* host hook as a trigger but only RENDERS on these. Absent = the package
|
|
58
|
+
* never saved a placement selection (unrestricted, legacy).
|
|
59
|
+
*/
|
|
60
|
+
allowedPlacements?: string[];
|
|
61
|
+
}
|
|
62
|
+
/** Response of POST /v1/serve/batch. */
|
|
63
|
+
interface BatchResponse {
|
|
64
|
+
ads: Ad[];
|
|
65
|
+
fallback?: Fallback | null;
|
|
66
|
+
config: RemoteConfig;
|
|
67
|
+
allowedPlacements?: string[];
|
|
68
|
+
}
|
|
69
|
+
/** Options accepted by every public `sponsor.*` call. */
|
|
70
|
+
interface SponsorOptions {
|
|
71
|
+
publisherKey: string;
|
|
72
|
+
packageName: string;
|
|
73
|
+
placement: string;
|
|
74
|
+
host?: Host;
|
|
75
|
+
/** Override the API origin (default https://api.opencrater.to, or OPENCRATER_API_ORIGIN). */
|
|
76
|
+
apiOrigin?: string;
|
|
77
|
+
}
|
|
78
|
+
/** A preloaded ad waiting in the local pool. */
|
|
79
|
+
interface PooledAd {
|
|
80
|
+
ad: Ad;
|
|
81
|
+
/** Epoch ms after which this pooled ad must not be rendered. */
|
|
82
|
+
renderBy: number;
|
|
83
|
+
}
|
|
84
|
+
/** Persistent on-disk state (~/.config/opencrater/state.json). */
|
|
85
|
+
interface OpenCraterState {
|
|
86
|
+
installId: string;
|
|
87
|
+
/** Epoch ms of the last rendered card (frequency cap anchor). 0 = never. */
|
|
88
|
+
lastShownAt: number;
|
|
89
|
+
optOut: boolean;
|
|
90
|
+
/** Whether the one-time first-run disclosure line has been shown. */
|
|
91
|
+
disclosureShown: boolean;
|
|
92
|
+
cachedConfig: RemoteConfig | null;
|
|
93
|
+
/** Epoch ms when cachedConfig was fetched. 0 = never. */
|
|
94
|
+
configFetchedAt: number;
|
|
95
|
+
pool: PooledAd[];
|
|
96
|
+
/**
|
|
97
|
+
* Per-package render gate, cached from serve responses: package name →
|
|
98
|
+
* hooks its owner selected. A package with no entry is unrestricted.
|
|
99
|
+
*/
|
|
100
|
+
allowedPlacements: Record<string, string[]>;
|
|
101
|
+
/** Rolling anonymized session topics (recsys signal), recency-stamped. */
|
|
102
|
+
sessionTopics: {
|
|
103
|
+
topic: string;
|
|
104
|
+
at: number;
|
|
105
|
+
}[];
|
|
106
|
+
/**
|
|
107
|
+
* Publisher integrations wired on this machine: each is the (key, package)
|
|
108
|
+
* a `opencrater on --key … --package …` ran with. The auto-integrator
|
|
109
|
+
* re-wires every detected host for each of these (incl. hosts the user
|
|
110
|
+
* installs LATER), so a new host gets connected on its own. */
|
|
111
|
+
integrations: {
|
|
112
|
+
key: string;
|
|
113
|
+
package: string;
|
|
114
|
+
}[];
|
|
115
|
+
}
|
|
116
|
+
declare const DEFAULT_CONFIG: RemoteConfig;
|
|
117
|
+
/** Claude Code hook events OpenCrater supports as placements. */
|
|
118
|
+
declare const HOOK_CATALOG: readonly ["SessionStart", "SessionEnd", "Stop", "PostToolUse", "Notification"];
|
|
119
|
+
type HookEvent = (typeof HOOK_CATALOG)[number];
|
|
120
|
+
|
|
121
|
+
interface RenderCardInput {
|
|
122
|
+
/** e.g. "Neon" — rendered as "Sponsored · Neon". Empty -> just "Sponsored". */
|
|
123
|
+
sponsorLabel: string;
|
|
124
|
+
title: string;
|
|
125
|
+
body: string;
|
|
126
|
+
url: string;
|
|
127
|
+
cta?: string;
|
|
128
|
+
}
|
|
129
|
+
interface RenderOptions {
|
|
130
|
+
/** Terminal column count; the card caps at min(width, 60). */
|
|
131
|
+
width?: number;
|
|
132
|
+
color?: boolean;
|
|
133
|
+
hyperlinks?: boolean;
|
|
134
|
+
/** Prepend the one-time first-run disclosure line. */
|
|
135
|
+
disclosure?: boolean;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Render a rounded box-drawing sponsor card. Pure string-in/string-out
|
|
139
|
+
* (no I/O) so it is trivially testable. Always labeled "Sponsored".
|
|
140
|
+
*/
|
|
141
|
+
declare function renderCard(card: RenderCardInput, opts?: RenderOptions): string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Terminal capability detection for inline images.
|
|
145
|
+
*
|
|
146
|
+
* Pure functions over an injected env/TTY flag so the matrix is trivially
|
|
147
|
+
* testable. Detection is deliberately conservative: emitting graphics escape
|
|
148
|
+
* sequences at a terminal that does not understand them prints garbage, which
|
|
149
|
+
* violates the SDK's "never disturb the host tool" contract.
|
|
150
|
+
*/
|
|
151
|
+
type Env = Record<string, string | undefined>;
|
|
152
|
+
/** Inline-image protocol the current terminal understands. */
|
|
153
|
+
type ImageProtocol = "iterm2" | "kitty" | "none";
|
|
154
|
+
/**
|
|
155
|
+
* Detect which inline-image protocol (if any) the terminal supports.
|
|
156
|
+
*
|
|
157
|
+
* - iTerm2 (`TERM_PROGRAM=iTerm.app` or `LC_TERMINAL=iTerm2`) → "iterm2"
|
|
158
|
+
* - WezTerm (`TERM_PROGRAM=WezTerm`) → "iterm2" (it implements that protocol)
|
|
159
|
+
* - Kitty (`TERM=xterm-kitty` or `KITTY_WINDOW_ID`) → "kitty"
|
|
160
|
+
* - tmux/screen → "none": both re-wrap escape sequences, and we cannot verify
|
|
161
|
+
* passthrough (`allow-passthrough`) from the environment alone.
|
|
162
|
+
* - Anything else, or no TTY → "none".
|
|
163
|
+
*/
|
|
164
|
+
declare function detectImageProtocol(env?: Env, isTTY?: boolean): ImageProtocol;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The text card for an ad of ANY creative format (pure, sync — safe for the
|
|
168
|
+
* non-TTY hook path, which must never fetch media):
|
|
169
|
+
* - text → the standard card
|
|
170
|
+
* - image/gif → standard card with body swapped for the text fallback
|
|
171
|
+
* - video → text fallback card, CTA defaults to "▶ Watch"
|
|
172
|
+
* - audio → text fallback card, CTA defaults to "🔊 Listen"
|
|
173
|
+
* The click URL is always carried, so the link stays reachable everywhere.
|
|
174
|
+
*/
|
|
175
|
+
declare function textCardForAd(ad: Ad): RenderCardInput;
|
|
176
|
+
interface MediaRenderOptions extends RenderOptions {
|
|
177
|
+
/** Override protocol detection (tests). Defaults to detectImageProtocol(). */
|
|
178
|
+
protocol?: ImageProtocol;
|
|
179
|
+
/** Override the fetch implementation (tests). Defaults to global fetch. */
|
|
180
|
+
fetchImpl?: typeof fetch;
|
|
181
|
+
timeoutMs?: number;
|
|
182
|
+
maxBytes?: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Render an ad of any creative format to a string. Image/GIF creatives in a
|
|
186
|
+
* capable terminal get the inline image ABOVE the standard text card (the
|
|
187
|
+
* sponsor label, body and click URL always remain as text). Everything else,
|
|
188
|
+
* and every failure, degrades to the text card. Never throws, never plays
|
|
189
|
+
* media: video/audio are click-through only.
|
|
190
|
+
*/
|
|
191
|
+
declare function renderAd(ad: Ad, opts?: MediaRenderOptions): Promise<string>;
|
|
192
|
+
|
|
193
|
+
/** Keep in sync with package.json (bundled, so we avoid a runtime fs read).
|
|
194
|
+
* AUTO-GENERATED by scripts/sync-version.mjs on `npm version`. */
|
|
195
|
+
declare const SDK_VERSION = "1.0.0";
|
|
196
|
+
|
|
197
|
+
/** Public API. Every method is fail-silent: it never throws. */
|
|
198
|
+
declare const sponsor: {
|
|
199
|
+
/** Fetch + render + report an impression. Resolves true if rendered. */
|
|
200
|
+
show(opts: SponsorOptions): Promise<boolean>;
|
|
201
|
+
/** Fetch an ad without rendering. Resolves to the Ad or null. */
|
|
202
|
+
fetch(opts: SponsorOptions): Promise<Ad | null>;
|
|
203
|
+
/** Fill the local preload pool. Resolves to the number of ads pooled. */
|
|
204
|
+
preload(opts: SponsorOptions): Promise<number>;
|
|
205
|
+
/** Render a pooled ad without network on the hot path. */
|
|
206
|
+
renderFromPool(opts: SponsorOptions): Promise<boolean>;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export { type Ad, type BatchResponse, type Creative, type CreativeFormat, DEFAULT_CONFIG, type Fallback, HOOK_CATALOG, type HookEvent, type Host, type ImageProtocol, type MediaRenderOptions, type OpenCraterState, type PooledAd, type RemoteConfig, type RenderCardInput, type RenderOptions, SDK_VERSION, type ServeResponse, type SponsorOptions, detectImageProtocol, renderAd, renderCard, sponsor, textCardForAd };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/** Host environment the SDK is running inside. */
|
|
2
|
+
type Host = "claude_code" | "codex" | "openclaw" | "gemini_cli" | "copilot_cli" | "generic";
|
|
3
|
+
/** Creative formats the serve API can return. Text always renders; rich
|
|
4
|
+
* media degrades to the text fallback when the terminal can't display it. */
|
|
5
|
+
type CreativeFormat = "text" | "logo" | "image" | "gif" | "video" | "audio";
|
|
6
|
+
/** Creative payload. `mediaUrl`/`textFallback` accompany non-text formats. */
|
|
7
|
+
interface Creative {
|
|
8
|
+
format: CreativeFormat;
|
|
9
|
+
title: string;
|
|
10
|
+
body: string;
|
|
11
|
+
cta?: string;
|
|
12
|
+
/** Hosted asset URL for image/gif/video/audio creatives. */
|
|
13
|
+
mediaUrl?: string;
|
|
14
|
+
/** pixel-art variant authored at the terminal grid (painter fast path) */
|
|
15
|
+
mediaPixelUrl?: string;
|
|
16
|
+
/** optional audio track that plays when the card renders (any format) */
|
|
17
|
+
audioUrl?: string;
|
|
18
|
+
/** Upload-time text fallback rendered when rich media can't display. */
|
|
19
|
+
textFallback?: string;
|
|
20
|
+
}
|
|
21
|
+
/** A served sponsor ad. `clickUrl` is the per-impression tracked redirect. */
|
|
22
|
+
interface Ad {
|
|
23
|
+
impressionId: string;
|
|
24
|
+
/** Campaign identity — used for LOCAL politeness (dismiss cooldown). */
|
|
25
|
+
campaignId?: string;
|
|
26
|
+
clickUrl: string;
|
|
27
|
+
sponsorLabel: string;
|
|
28
|
+
creative: Creative;
|
|
29
|
+
}
|
|
30
|
+
/** Publisher funding fallback rendered when no campaign fills. */
|
|
31
|
+
interface Fallback {
|
|
32
|
+
title: string;
|
|
33
|
+
body: string;
|
|
34
|
+
url: string;
|
|
35
|
+
}
|
|
36
|
+
/** Server-controlled SDK config (cached locally between fetches). */
|
|
37
|
+
interface RemoteConfig {
|
|
38
|
+
minIntervalSeconds: number;
|
|
39
|
+
serveTimeoutMs: number;
|
|
40
|
+
preloadPoolSize: number;
|
|
41
|
+
killSwitch: boolean;
|
|
42
|
+
/** How long a painted card stays on screen, in seconds (admin-tunable). */
|
|
43
|
+
displayDurationSeconds: number;
|
|
44
|
+
/** Minimum SDK version the platform wants running. A runtime below this
|
|
45
|
+
* force-updates immediately (bypassing the daily cycle) — the lever to push
|
|
46
|
+
* a critical fix without waiting. Empty = no floor. */
|
|
47
|
+
minSdkVersion: string;
|
|
48
|
+
}
|
|
49
|
+
/** Response of POST /v1/serve. */
|
|
50
|
+
interface ServeResponse {
|
|
51
|
+
fill: boolean;
|
|
52
|
+
ad?: Ad;
|
|
53
|
+
fallback?: Fallback | null;
|
|
54
|
+
config: RemoteConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Hooks the package owner selected for this host. The SDK registers every
|
|
57
|
+
* host hook as a trigger but only RENDERS on these. Absent = the package
|
|
58
|
+
* never saved a placement selection (unrestricted, legacy).
|
|
59
|
+
*/
|
|
60
|
+
allowedPlacements?: string[];
|
|
61
|
+
}
|
|
62
|
+
/** Response of POST /v1/serve/batch. */
|
|
63
|
+
interface BatchResponse {
|
|
64
|
+
ads: Ad[];
|
|
65
|
+
fallback?: Fallback | null;
|
|
66
|
+
config: RemoteConfig;
|
|
67
|
+
allowedPlacements?: string[];
|
|
68
|
+
}
|
|
69
|
+
/** Options accepted by every public `sponsor.*` call. */
|
|
70
|
+
interface SponsorOptions {
|
|
71
|
+
publisherKey: string;
|
|
72
|
+
packageName: string;
|
|
73
|
+
placement: string;
|
|
74
|
+
host?: Host;
|
|
75
|
+
/** Override the API origin (default https://api.opencrater.to, or OPENCRATER_API_ORIGIN). */
|
|
76
|
+
apiOrigin?: string;
|
|
77
|
+
}
|
|
78
|
+
/** A preloaded ad waiting in the local pool. */
|
|
79
|
+
interface PooledAd {
|
|
80
|
+
ad: Ad;
|
|
81
|
+
/** Epoch ms after which this pooled ad must not be rendered. */
|
|
82
|
+
renderBy: number;
|
|
83
|
+
}
|
|
84
|
+
/** Persistent on-disk state (~/.config/opencrater/state.json). */
|
|
85
|
+
interface OpenCraterState {
|
|
86
|
+
installId: string;
|
|
87
|
+
/** Epoch ms of the last rendered card (frequency cap anchor). 0 = never. */
|
|
88
|
+
lastShownAt: number;
|
|
89
|
+
optOut: boolean;
|
|
90
|
+
/** Whether the one-time first-run disclosure line has been shown. */
|
|
91
|
+
disclosureShown: boolean;
|
|
92
|
+
cachedConfig: RemoteConfig | null;
|
|
93
|
+
/** Epoch ms when cachedConfig was fetched. 0 = never. */
|
|
94
|
+
configFetchedAt: number;
|
|
95
|
+
pool: PooledAd[];
|
|
96
|
+
/**
|
|
97
|
+
* Per-package render gate, cached from serve responses: package name →
|
|
98
|
+
* hooks its owner selected. A package with no entry is unrestricted.
|
|
99
|
+
*/
|
|
100
|
+
allowedPlacements: Record<string, string[]>;
|
|
101
|
+
/** Rolling anonymized session topics (recsys signal), recency-stamped. */
|
|
102
|
+
sessionTopics: {
|
|
103
|
+
topic: string;
|
|
104
|
+
at: number;
|
|
105
|
+
}[];
|
|
106
|
+
/**
|
|
107
|
+
* Publisher integrations wired on this machine: each is the (key, package)
|
|
108
|
+
* a `opencrater on --key … --package …` ran with. The auto-integrator
|
|
109
|
+
* re-wires every detected host for each of these (incl. hosts the user
|
|
110
|
+
* installs LATER), so a new host gets connected on its own. */
|
|
111
|
+
integrations: {
|
|
112
|
+
key: string;
|
|
113
|
+
package: string;
|
|
114
|
+
}[];
|
|
115
|
+
}
|
|
116
|
+
declare const DEFAULT_CONFIG: RemoteConfig;
|
|
117
|
+
/** Claude Code hook events OpenCrater supports as placements. */
|
|
118
|
+
declare const HOOK_CATALOG: readonly ["SessionStart", "SessionEnd", "Stop", "PostToolUse", "Notification"];
|
|
119
|
+
type HookEvent = (typeof HOOK_CATALOG)[number];
|
|
120
|
+
|
|
121
|
+
interface RenderCardInput {
|
|
122
|
+
/** e.g. "Neon" — rendered as "Sponsored · Neon". Empty -> just "Sponsored". */
|
|
123
|
+
sponsorLabel: string;
|
|
124
|
+
title: string;
|
|
125
|
+
body: string;
|
|
126
|
+
url: string;
|
|
127
|
+
cta?: string;
|
|
128
|
+
}
|
|
129
|
+
interface RenderOptions {
|
|
130
|
+
/** Terminal column count; the card caps at min(width, 60). */
|
|
131
|
+
width?: number;
|
|
132
|
+
color?: boolean;
|
|
133
|
+
hyperlinks?: boolean;
|
|
134
|
+
/** Prepend the one-time first-run disclosure line. */
|
|
135
|
+
disclosure?: boolean;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Render a rounded box-drawing sponsor card. Pure string-in/string-out
|
|
139
|
+
* (no I/O) so it is trivially testable. Always labeled "Sponsored".
|
|
140
|
+
*/
|
|
141
|
+
declare function renderCard(card: RenderCardInput, opts?: RenderOptions): string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Terminal capability detection for inline images.
|
|
145
|
+
*
|
|
146
|
+
* Pure functions over an injected env/TTY flag so the matrix is trivially
|
|
147
|
+
* testable. Detection is deliberately conservative: emitting graphics escape
|
|
148
|
+
* sequences at a terminal that does not understand them prints garbage, which
|
|
149
|
+
* violates the SDK's "never disturb the host tool" contract.
|
|
150
|
+
*/
|
|
151
|
+
type Env = Record<string, string | undefined>;
|
|
152
|
+
/** Inline-image protocol the current terminal understands. */
|
|
153
|
+
type ImageProtocol = "iterm2" | "kitty" | "none";
|
|
154
|
+
/**
|
|
155
|
+
* Detect which inline-image protocol (if any) the terminal supports.
|
|
156
|
+
*
|
|
157
|
+
* - iTerm2 (`TERM_PROGRAM=iTerm.app` or `LC_TERMINAL=iTerm2`) → "iterm2"
|
|
158
|
+
* - WezTerm (`TERM_PROGRAM=WezTerm`) → "iterm2" (it implements that protocol)
|
|
159
|
+
* - Kitty (`TERM=xterm-kitty` or `KITTY_WINDOW_ID`) → "kitty"
|
|
160
|
+
* - tmux/screen → "none": both re-wrap escape sequences, and we cannot verify
|
|
161
|
+
* passthrough (`allow-passthrough`) from the environment alone.
|
|
162
|
+
* - Anything else, or no TTY → "none".
|
|
163
|
+
*/
|
|
164
|
+
declare function detectImageProtocol(env?: Env, isTTY?: boolean): ImageProtocol;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The text card for an ad of ANY creative format (pure, sync — safe for the
|
|
168
|
+
* non-TTY hook path, which must never fetch media):
|
|
169
|
+
* - text → the standard card
|
|
170
|
+
* - image/gif → standard card with body swapped for the text fallback
|
|
171
|
+
* - video → text fallback card, CTA defaults to "▶ Watch"
|
|
172
|
+
* - audio → text fallback card, CTA defaults to "🔊 Listen"
|
|
173
|
+
* The click URL is always carried, so the link stays reachable everywhere.
|
|
174
|
+
*/
|
|
175
|
+
declare function textCardForAd(ad: Ad): RenderCardInput;
|
|
176
|
+
interface MediaRenderOptions extends RenderOptions {
|
|
177
|
+
/** Override protocol detection (tests). Defaults to detectImageProtocol(). */
|
|
178
|
+
protocol?: ImageProtocol;
|
|
179
|
+
/** Override the fetch implementation (tests). Defaults to global fetch. */
|
|
180
|
+
fetchImpl?: typeof fetch;
|
|
181
|
+
timeoutMs?: number;
|
|
182
|
+
maxBytes?: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Render an ad of any creative format to a string. Image/GIF creatives in a
|
|
186
|
+
* capable terminal get the inline image ABOVE the standard text card (the
|
|
187
|
+
* sponsor label, body and click URL always remain as text). Everything else,
|
|
188
|
+
* and every failure, degrades to the text card. Never throws, never plays
|
|
189
|
+
* media: video/audio are click-through only.
|
|
190
|
+
*/
|
|
191
|
+
declare function renderAd(ad: Ad, opts?: MediaRenderOptions): Promise<string>;
|
|
192
|
+
|
|
193
|
+
/** Keep in sync with package.json (bundled, so we avoid a runtime fs read).
|
|
194
|
+
* AUTO-GENERATED by scripts/sync-version.mjs on `npm version`. */
|
|
195
|
+
declare const SDK_VERSION = "1.0.0";
|
|
196
|
+
|
|
197
|
+
/** Public API. Every method is fail-silent: it never throws. */
|
|
198
|
+
declare const sponsor: {
|
|
199
|
+
/** Fetch + render + report an impression. Resolves true if rendered. */
|
|
200
|
+
show(opts: SponsorOptions): Promise<boolean>;
|
|
201
|
+
/** Fetch an ad without rendering. Resolves to the Ad or null. */
|
|
202
|
+
fetch(opts: SponsorOptions): Promise<Ad | null>;
|
|
203
|
+
/** Fill the local preload pool. Resolves to the number of ads pooled. */
|
|
204
|
+
preload(opts: SponsorOptions): Promise<number>;
|
|
205
|
+
/** Render a pooled ad without network on the hot path. */
|
|
206
|
+
renderFromPool(opts: SponsorOptions): Promise<boolean>;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export { type Ad, type BatchResponse, type Creative, type CreativeFormat, DEFAULT_CONFIG, type Fallback, HOOK_CATALOG, type HookEvent, type Host, type ImageProtocol, type MediaRenderOptions, type OpenCraterState, type PooledAd, type RemoteConfig, type RenderCardInput, type RenderOptions, SDK_VERSION, type ServeResponse, type SponsorOptions, detectImageProtocol, renderAd, renderCard, sponsor, textCardForAd };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
'use strict';var crypto=require('crypto'),d=require('fs'),ee=require('os'),b=require('path');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var d__namespace=/*#__PURE__*/_interopNamespace(d);var ee__namespace=/*#__PURE__*/_interopNamespace(ee);var b__namespace=/*#__PURE__*/_interopNamespace(b);var D=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var C={minIntervalSeconds:600,serveTimeoutMs:2500,preloadPoolSize:3,killSwitch:false,displayDurationSeconds:25,minSdkVersion:""};var re=["SessionStart","SessionEnd","Stop","PostToolUse","Notification"];var N="1.0.0";var ie="https://api.opencrater.to";function z(e,t=process.env){let n=t.OPENCRATER_API_ORIGIN;return (e??(n&&n.trim()!==""?n:ie)).replace(/\/+$/,"")}function l(...e){try{if(process.env.OPENCRATER_DEBUG!=="1")return;console.error("[opencrater]",...e);try{let t=D("os"),n=D("fs"),r=D("path");n.appendFileSync(r.join(t.homedir(),".config","opencrater","hook.log"),`${new Date().toISOString()} [opencrater] ${e.map(o=>String(o)).join(" ")}
|
|
2
|
+
`);}catch{}}catch{}}function E(e){return typeof e=="number"&&Number.isFinite(e)}function K(e){let t=C;if(typeof e!="object"||e===null)return {...t};let n=e;return {minIntervalSeconds:E(n.minIntervalSeconds)?n.minIntervalSeconds:t.minIntervalSeconds,serveTimeoutMs:E(n.serveTimeoutMs)?n.serveTimeoutMs:t.serveTimeoutMs,preloadPoolSize:E(n.preloadPoolSize)?n.preloadPoolSize:t.preloadPoolSize,killSwitch:n.killSwitch===true,displayDurationSeconds:E(n.displayDurationSeconds)?n.displayDurationSeconds:t.displayDurationSeconds,minSdkVersion:typeof n.minSdkVersion=="string"?n.minSdkVersion:t.minSdkVersion}}async function B(e,t,n,r){try{let o=await fetch(`${e}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(r)});return o.ok?await o.json():(l(`POST ${t} -> HTTP ${o.status}`),null)}catch(o){return l(`POST ${t} failed:`,o),null}}function W(e,t){let n=e.host??"generic";return {publisherKey:e.publisherKey,packageName:e.packageName,placement:e.placement,host:n,sdkVersion:N,installId:t.installId,os:process.platform,termProgram:process.env.TERM_PROGRAM??void 0,topics:t.topics&&t.topics.length>0?t.topics:void 0}}async function j(e,t){let n=await B(t.origin,"/v1/serve",W(e,t),t.timeoutMs);if(typeof n!="object"||n===null)return null;let r=n;if(typeof r.fill!="boolean")return null;let o={fill:r.fill,fallback:r.fallback??null,config:K(r.config),...Array.isArray(r.allowedPlacements)?{allowedPlacements:r.allowedPlacements.filter(i=>typeof i=="string")}:{}};return r.ad!==void 0&&r.ad!==null&&(o.ad=r.ad),o}async function q(e,t,n){let r=await B(n.origin,"/v1/serve/batch",{...W(e,n),count:t},n.timeoutMs);if(typeof r!="object"||r===null)return null;let o=r;return Array.isArray(o.ads)?{ads:o.ads,fallback:o.fallback??null,config:K(o.config),...Array.isArray(o.allowedPlacements)?{allowedPlacements:o.allowedPlacements.filter(i=>typeof i=="string")}:{}}:null}function U(e,t){return B(t.origin,"/v1/events/impression",{impressionId:e},t.timeoutMs).then(()=>{}).catch(()=>{})}var se=new RegExp("\x1B\\[[0-9;]*m|\x1B\\]8;;[^\x07\x1B]*(?:\x07|\x1B\\\\)","g"),k={dim:"\x1B[2m",bold:"\x1B[1m",reset:"\x1B[0m"},ae=60,ce=24,le="\u2139 This project is supported by sponsor messages via OpenCrater. Opt out: `npx opencrater off` or OPENCRATER_DISABLE=1";function ue(e){return e.replace(se,"").length}function h(e,t){return t<=0?"":e.length<=t?e:t===1?"\u2026":e.slice(0,t-1).trimEnd()+"\u2026"}function pe(e,t,n){let r=e.split(/\s+/).filter(c=>c.length>0),o=[],i="";for(let c of r){let p=i===""?c:`${i} ${c}`;if(p.length<=t)i=p;else if(i!==""&&o.push(i),i=c.length>t?h(c,t):c,o.length>=n)break}i!==""&&o.length<n&&o.push(i),o.length>n&&(o.length=n);let a=o.join(" "),s=o.length-1,u=o[s];return u!==void 0&&a.length<r.join(" ").length&&(o[s]=h(`${u}\u2026`,t)),o}function R(e=process.env,t=!!process.stdout.isTTY){if(!t)return false;if(e.FORCE_HYPERLINK!==void 0&&e.FORCE_HYPERLINK!=="0")return true;let n=e.TERM_PROGRAM??"";return !!(["iTerm.app","WezTerm","ghostty","Hyper","vscode","Tabby"].includes(n)||e.KITTY_WINDOW_ID||e.WT_SESSION||Number(e.VTE_VERSION??"0")>=5e3)}function P(e=process.env,t=!!process.stdout.isTTY){return !(e.NO_COLOR!==void 0&&e.NO_COLOR!==""||!t||(e.TERM??"")==="dumb")}function de(e,t){return `\x1B]8;;${e}\x07${t}\x1B]8;;\x07`}function x(e){let t={sponsorLabel:e.sponsorLabel,title:e.creative.title,body:e.creative.body,url:e.clickUrl};return e.creative.cta!==void 0&&(t.cta=e.creative.cta),t}function J(e){return {sponsorLabel:"",title:e.title,body:e.body,url:e.url}}function m(e,t={}){let n=t.width??process.stdout.columns??80,o=Math.max(ce,Math.min(n,ae))-4,i=t.color??P(),a=t.hyperlinks??R(),s=(f,M)=>i?`${M}${f}${k.reset}`:f,u=e.sponsorLabel?h(`Sponsored \xB7 ${e.sponsorLabel}`,o):"Sponsored",c=[];c.push(s(u,k.dim)),e.title!==e.sponsorLabel&&c.push(s(h(e.title,o),k.bold));for(let f of pe(e.body,o,2))c.push(f);let p="\u2192 ";if(a){let f=h(e.cta??e.url,o-p.length);c.push(p+s(de(e.url,f),k.dim));}else e.cta&&c.push(h(e.cta,o)),c.push(p+s(h(e.url,o-p.length),k.dim));let A=`\u256D${"\u2500".repeat(o+2)}\u256E`,O=`\u2570${"\u2500".repeat(o+2)}\u256F`,L=c.map(f=>{let M=" ".repeat(Math.max(0,o-ue(f)));return `\u2502 ${f}${M} \u2502`}),S=[];return t.disclosure&&S.push(s(le,k.dim)),S.push(A,...L,O),S.join(`
|
|
3
|
+
`)+`
|
|
4
|
+
`}function X(e){return e!==void 0&&e!==""}function Y(e=process.env,t=!!process.stdout.isTTY){if(!t)return "none";let n=e.TERM??"";if(X(e.TMUX)||n.startsWith("tmux")||n.startsWith("screen"))return "none";let r=e.TERM_PROGRAM??"";return r==="iTerm.app"||e.LC_TERMINAL==="iTerm2"||r==="WezTerm"?"iterm2":n==="xterm-kitty"||X(e.KITTY_WINDOW_ID)?"kitty":"none"}var w="\x1B",fe="\x07",me=2e3,ge=2*1024*1024,ye=new Set(["image/png","image/jpeg","image/gif","image/webp"]),v=4096;async function Se(e,t=fetch,n={}){let r=n.timeoutMs??me,o=n.maxBytes??ge;try{let i=await t(e,{signal:AbortSignal.timeout(r)});if(!i.ok)return l(`media: HTTP ${i.status} for ${e}`),null;let a=(i.headers.get("content-type")??"").split(";")[0].trim().toLowerCase();if(!ye.has(a))return l(`media: disallowed content-type "${a}" for ${e}`),null;let s=Number(i.headers.get("content-length")??"0");if(Number.isFinite(s)&&s>o)return l(`media: content-length ${s} exceeds ${o} for ${e}`),null;let u=i.body;if(u&&typeof u.getReader=="function"){let p=u.getReader(),A=[],O=0;for(;;){let{done:L,value:S}=await p.read();if(L)break;if(S!==void 0){if(O+=S.byteLength,O>o)return await p.cancel().catch(()=>{}),l(`media: stream exceeded ${o} bytes for ${e}`),null;A.push(S);}}return Buffer.concat(A)}let c=Buffer.from(await i.arrayBuffer());return c.byteLength>o?(l(`media: body ${c.byteLength} bytes exceeds ${o} for ${e}`),null):c}catch(i){return l(`media: fetch failed for ${e}:`,i),null}}function he(e){let t=e.toString("base64");return `${w}]1337;File=inline=1;size=${e.byteLength};width=auto:${t}${fe}`}function be(e){let t=e.toString("base64");if(t.length<=v)return `${w}_Gf=100,a=T;${t}${w}\\`;let n=[];for(let r=0;r<t.length;r+=v){let o=t.slice(r,r+v),a=`m=${r+v>=t.length?0:1}`,s=r===0?`f=100,a=T,${a}`:a;n.push(`${w}_G${s};${o}${w}\\`);}return n.join("")}function _(e){let t=x(e),n=e.creative;switch(n.format){case "image":case "gif":return {...t,body:n.textFallback??t.body};case "video":return {...t,body:n.textFallback??t.body,cta:t.cta??"\u25B6 Watch"};case "audio":return {...t,body:n.textFallback??t.body,cta:t.cta??"\u{1F50A} Listen"};default:return t}}async function H(e,t={}){try{let n=e.creative;if(n.format!=="image"&&n.format!=="gif")return m(_(e),t);let r=t.protocol??Y();if(r==="none"||n.mediaUrl===void 0||n.mediaUrl==="")return m(_(e),t);let o={};t.timeoutMs!==void 0&&(o.timeoutMs=t.timeoutMs),t.maxBytes!==void 0&&(o.maxBytes=t.maxBytes);let i=await Se(n.mediaUrl,t.fetchImpl??fetch,o);return i===null||i.byteLength===0?m(_(e),t):(r==="kitty"?be(i):he(i))+`
|
|
5
|
+
`+m(x(e),t)}catch(n){return l("media: render failed, falling back to text:",n),m(x(e),t)}}function Ce(e,t){return e.filter(n=>n.renderBy>t)}function Z(e,t,n=18e5){return e.filter(r=>r&&typeof r.impressionId=="string"&&typeof r.clickUrl=="string"&&r.creative&&typeof r.creative.title=="string").map(r=>({ad:r,renderBy:t+n}))}function Q(e,t){let n=Ce(e.pool,t),r=n.shift();return {ad:r?r.ad:null,pool:n}}function we(e=process.env){let t=e.XDG_CONFIG_HOME,n=t&&t.trim()!==""?t:b__namespace.join(ee__namespace.homedir(),".config");return b__namespace.join(n,"opencrater")}function te(e=process.env){return b__namespace.join(we(e),"state.json")}function ne(){return {installId:crypto.randomUUID(),lastShownAt:0,optOut:false,disclosureShown:false,cachedConfig:null,configFetchedAt:0,pool:[],allowedPlacements:{},sessionTopics:[],integrations:[]}}function y(e){return typeof e=="number"&&Number.isFinite(e)}function Ie(e){if(typeof e!="object"||e===null)return null;let t=e;return !y(t.minIntervalSeconds)||!y(t.serveTimeoutMs)||!y(t.preloadPoolSize)||typeof t.killSwitch!="boolean"?null:{minIntervalSeconds:t.minIntervalSeconds,serveTimeoutMs:t.serveTimeoutMs,preloadPoolSize:t.preloadPoolSize,killSwitch:t.killSwitch,displayDurationSeconds:y(t.displayDurationSeconds)?t.displayDurationSeconds:25,minSdkVersion:typeof t.minSdkVersion=="string"?t.minSdkVersion:""}}function Te(e){if(!Array.isArray(e))return [];let t=[];for(let n of e){if(typeof n!="object"||n===null)continue;let r=n,o=r.ad;if(!y(r.renderBy)||typeof o!="object"||o===null||typeof o.impressionId!="string"||typeof o.clickUrl!="string"||typeof o.sponsorLabel!="string"||typeof o.creative!="object"||o.creative===null)continue;let i=o.creative;typeof i.title!="string"||typeof i.body!="string"||t.push({ad:{impressionId:o.impressionId,...typeof o.campaignId=="string"?{campaignId:o.campaignId}:{},clickUrl:o.clickUrl,sponsorLabel:o.sponsorLabel,creative:{format:"text",title:i.title,body:i.body,...typeof i.cta=="string"?{cta:i.cta}:{}}},renderBy:r.renderBy});}return t}function Ae(e){if(typeof e!="object"||e===null||Array.isArray(e))return {};let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r))continue;let o=r.filter(i=>typeof i=="string"&&i.length<=64);t[n]=o.slice(0,64);}return t}function Oe(e){if(!Array.isArray(e))return [];let t=[];for(let n of e){if(typeof n!="object"||n===null)continue;let r=n;if(!(typeof r.topic!="string"||!y(r.at))&&(t.push({topic:r.topic.slice(0,32),at:r.at}),t.length>=24))break}return t}function Ee(e){if(!Array.isArray(e))return [];let t=[],n=new Set;for(let r of e){if(typeof r!="object"||r===null)continue;let o=r;if(typeof o.key!="string"||typeof o.package!="string"||o.key===""||o.package==="")continue;let i=`${o.package}\0${o.key}`;if(!n.has(i)&&(n.add(i),t.push({key:o.key,package:o.package}),t.length>=32))break}return t}function Re(e){let t=ne();if(typeof e!="object"||e===null)return t;let n=e;return {installId:typeof n.installId=="string"&&n.installId.length>0?n.installId:t.installId,lastShownAt:y(n.lastShownAt)&&n.lastShownAt>=0?n.lastShownAt:0,optOut:n.optOut===true,disclosureShown:n.disclosureShown===true,cachedConfig:Ie(n.cachedConfig),allowedPlacements:Ae(n.allowedPlacements),sessionTopics:Oe(n.sessionTopics),integrations:Ee(n.integrations),configFetchedAt:y(n.configFetchedAt)&&n.configFetchedAt>=0?n.configFetchedAt:0,pool:Te(n.pool)}}function I(e=process.env){let t=te(e);try{let n=d__namespace.readFileSync(t,"utf8"),r=JSON.parse(n);return Re(r)}catch{let n=ne();try{g(n,e);}catch{}return n}}function g(e,t=process.env){let n=te(t),r=b__namespace.dirname(n);d__namespace.mkdirSync(r,{recursive:true});let o=b__namespace.join(r,`.state.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);d__namespace.writeFileSync(o,JSON.stringify(e,null,2)+`
|
|
6
|
+
`,"utf8");let i=new Set(["EPERM","EACCES","EBUSY","EEXIST"]);for(let a=0;;a++)try{d__namespace.renameSync(o,n);return}catch(s){let u=s.code??"";if(a>=4||!i.has(u)){try{d__namespace.rmSync(o,{force:!0});}catch{}if(a>=4)return;throw s}try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,15*(a+1));}catch{}}}var Pe=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTIONS","GITLAB_CI","CIRCLECI","TRAVIS","BUILDKITE","JENKINS_URL","TEAMCITY_VERSION","TF_BUILD","APPVEYOR","CODEBUILD_BUILD_ID","DRONE","NETLIFY","VERCEL"];function G(e){return e!==void 0&&e!==""&&e!=="0"&&e.toLowerCase()!=="false"}function xe(e){return G(e.OPENCRATER_DISABLE)||G(e.TSN_DISABLE)}function ve(e){return Pe.some(t=>G(e[t]))}function V(e){return e?{...C,...e}:C}function T(e,t={}){if(xe(e.env))return "env_disabled";if(e.state.optOut)return "opt_out";let n=V(e.state.cachedConfig);if(n.killSwitch)return "kill_switch";if(ve(e.env))return "ci";if(!t.skipTTY&&!e.isTTY)return "not_tty";if(!t.skipFrequency){let r=n.minIntervalSeconds*1e3;if(e.state.lastShownAt>0&&e.now-e.state.lastShownAt<r)return "frequency"}return null}async function $(e){try{return await e()}catch(t){return l("suppressed error:",t),null}}function F(e,t){let n=V(t.cachedConfig);return {origin:z(e.apiOrigin),timeoutMs:n.serveTimeoutMs,installId:t.installId,config:n}}function _e(e,t){let n=!t.disclosureShown,r=m(e,{width:process.stdout.columns??80,color:P(),hyperlinks:R(),disclosure:n});return process.stdout.write(r),{...t,lastShownAt:Date.now(),disclosureShown:true}}async function oe(e,t){let n=await H(e,{width:process.stdout.columns??80,color:P(),hyperlinks:R(),disclosure:!t.disclosureShown});return process.stdout.write(n),{...t,lastShownAt:Date.now(),disclosureShown:true}}async function $e(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()},{skipFrequency:true});if(n!==null)return l("fetch suppressed:",n),null;let r=F(e,t),o=await j(e,r);return o?(g({...t,cachedConfig:o.config,configFetchedAt:Date.now()}),o.fill&&o.ad?o.ad:null):null}async function Fe(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()});if(n!==null)return l("suppressed:",n),false;let r=F(e,t),o=await j(e,r);return o?(t={...t,cachedConfig:o.config,configFetchedAt:Date.now()},o.fill&&o.ad?(t=await oe(o.ad,t),g(t),U(o.ad.impressionId,r),true):o.fallback?(t=_e(J(o.fallback),t),g(t),true):(g(t),false)):false}async function Le(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()},{skipTTY:true,skipFrequency:true});if(n!==null)return l("preload suppressed:",n),0;let r=F(e,t),o=Math.max(1,r.config.preloadPoolSize),i=await q(e,o,r);if(!i)return 0;let a=Date.now(),s=Z(i.ads,a);return g({...t,pool:s,cachedConfig:i.config,configFetchedAt:a}),s.length}async function Me(e){let t=I(),n=Date.now(),r=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:n});if(r!==null)return l("renderFromPool suppressed:",r),false;let{ad:o,pool:i}=Q(t,n);if(!o)return g({...t,pool:i}),false;let a=await oe(o,{...t,pool:i});g(a);let s=F(e,t);return U(o.impressionId,s),true}var st={show(e){return $(()=>Fe(e)).then(t=>t??false)},fetch(e){return $(()=>$e(e))},preload(e){return $(()=>Le(e)).then(t=>t??0)},renderFromPool(e){return $(()=>Me(e)).then(t=>t??false)}};exports.DEFAULT_CONFIG=C;exports.HOOK_CATALOG=re;exports.SDK_VERSION=N;exports.detectImageProtocol=Y;exports.renderAd=H;exports.renderCard=m;exports.sponsor=st;exports.textCardForAd=_;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import {randomUUID}from'crypto';import*as d from'fs';import*as ee from'os';import*as b from'path';var D=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var C={minIntervalSeconds:600,serveTimeoutMs:2500,preloadPoolSize:3,killSwitch:false,displayDurationSeconds:25,minSdkVersion:""};var re=["SessionStart","SessionEnd","Stop","PostToolUse","Notification"];var N="1.0.0";var ie="https://api.opencrater.to";function z(e,t=process.env){let n=t.OPENCRATER_API_ORIGIN;return (e??(n&&n.trim()!==""?n:ie)).replace(/\/+$/,"")}function l(...e){try{if(process.env.OPENCRATER_DEBUG!=="1")return;console.error("[opencrater]",...e);try{let t=D("os"),n=D("fs"),r=D("path");n.appendFileSync(r.join(t.homedir(),".config","opencrater","hook.log"),`${new Date().toISOString()} [opencrater] ${e.map(o=>String(o)).join(" ")}
|
|
2
|
+
`);}catch{}}catch{}}function E(e){return typeof e=="number"&&Number.isFinite(e)}function K(e){let t=C;if(typeof e!="object"||e===null)return {...t};let n=e;return {minIntervalSeconds:E(n.minIntervalSeconds)?n.minIntervalSeconds:t.minIntervalSeconds,serveTimeoutMs:E(n.serveTimeoutMs)?n.serveTimeoutMs:t.serveTimeoutMs,preloadPoolSize:E(n.preloadPoolSize)?n.preloadPoolSize:t.preloadPoolSize,killSwitch:n.killSwitch===true,displayDurationSeconds:E(n.displayDurationSeconds)?n.displayDurationSeconds:t.displayDurationSeconds,minSdkVersion:typeof n.minSdkVersion=="string"?n.minSdkVersion:t.minSdkVersion}}async function B(e,t,n,r){try{let o=await fetch(`${e}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(r)});return o.ok?await o.json():(l(`POST ${t} -> HTTP ${o.status}`),null)}catch(o){return l(`POST ${t} failed:`,o),null}}function W(e,t){let n=e.host??"generic";return {publisherKey:e.publisherKey,packageName:e.packageName,placement:e.placement,host:n,sdkVersion:N,installId:t.installId,os:process.platform,termProgram:process.env.TERM_PROGRAM??void 0,topics:t.topics&&t.topics.length>0?t.topics:void 0}}async function j(e,t){let n=await B(t.origin,"/v1/serve",W(e,t),t.timeoutMs);if(typeof n!="object"||n===null)return null;let r=n;if(typeof r.fill!="boolean")return null;let o={fill:r.fill,fallback:r.fallback??null,config:K(r.config),...Array.isArray(r.allowedPlacements)?{allowedPlacements:r.allowedPlacements.filter(i=>typeof i=="string")}:{}};return r.ad!==void 0&&r.ad!==null&&(o.ad=r.ad),o}async function q(e,t,n){let r=await B(n.origin,"/v1/serve/batch",{...W(e,n),count:t},n.timeoutMs);if(typeof r!="object"||r===null)return null;let o=r;return Array.isArray(o.ads)?{ads:o.ads,fallback:o.fallback??null,config:K(o.config),...Array.isArray(o.allowedPlacements)?{allowedPlacements:o.allowedPlacements.filter(i=>typeof i=="string")}:{}}:null}function U(e,t){return B(t.origin,"/v1/events/impression",{impressionId:e},t.timeoutMs).then(()=>{}).catch(()=>{})}var se=new RegExp("\x1B\\[[0-9;]*m|\x1B\\]8;;[^\x07\x1B]*(?:\x07|\x1B\\\\)","g"),k={dim:"\x1B[2m",bold:"\x1B[1m",reset:"\x1B[0m"},ae=60,ce=24,le="\u2139 This project is supported by sponsor messages via OpenCrater. Opt out: `npx opencrater off` or OPENCRATER_DISABLE=1";function ue(e){return e.replace(se,"").length}function h(e,t){return t<=0?"":e.length<=t?e:t===1?"\u2026":e.slice(0,t-1).trimEnd()+"\u2026"}function pe(e,t,n){let r=e.split(/\s+/).filter(c=>c.length>0),o=[],i="";for(let c of r){let p=i===""?c:`${i} ${c}`;if(p.length<=t)i=p;else if(i!==""&&o.push(i),i=c.length>t?h(c,t):c,o.length>=n)break}i!==""&&o.length<n&&o.push(i),o.length>n&&(o.length=n);let a=o.join(" "),s=o.length-1,u=o[s];return u!==void 0&&a.length<r.join(" ").length&&(o[s]=h(`${u}\u2026`,t)),o}function R(e=process.env,t=!!process.stdout.isTTY){if(!t)return false;if(e.FORCE_HYPERLINK!==void 0&&e.FORCE_HYPERLINK!=="0")return true;let n=e.TERM_PROGRAM??"";return !!(["iTerm.app","WezTerm","ghostty","Hyper","vscode","Tabby"].includes(n)||e.KITTY_WINDOW_ID||e.WT_SESSION||Number(e.VTE_VERSION??"0")>=5e3)}function P(e=process.env,t=!!process.stdout.isTTY){return !(e.NO_COLOR!==void 0&&e.NO_COLOR!==""||!t||(e.TERM??"")==="dumb")}function de(e,t){return `\x1B]8;;${e}\x07${t}\x1B]8;;\x07`}function x(e){let t={sponsorLabel:e.sponsorLabel,title:e.creative.title,body:e.creative.body,url:e.clickUrl};return e.creative.cta!==void 0&&(t.cta=e.creative.cta),t}function J(e){return {sponsorLabel:"",title:e.title,body:e.body,url:e.url}}function m(e,t={}){let n=t.width??process.stdout.columns??80,o=Math.max(ce,Math.min(n,ae))-4,i=t.color??P(),a=t.hyperlinks??R(),s=(f,M)=>i?`${M}${f}${k.reset}`:f,u=e.sponsorLabel?h(`Sponsored \xB7 ${e.sponsorLabel}`,o):"Sponsored",c=[];c.push(s(u,k.dim)),e.title!==e.sponsorLabel&&c.push(s(h(e.title,o),k.bold));for(let f of pe(e.body,o,2))c.push(f);let p="\u2192 ";if(a){let f=h(e.cta??e.url,o-p.length);c.push(p+s(de(e.url,f),k.dim));}else e.cta&&c.push(h(e.cta,o)),c.push(p+s(h(e.url,o-p.length),k.dim));let A=`\u256D${"\u2500".repeat(o+2)}\u256E`,O=`\u2570${"\u2500".repeat(o+2)}\u256F`,L=c.map(f=>{let M=" ".repeat(Math.max(0,o-ue(f)));return `\u2502 ${f}${M} \u2502`}),S=[];return t.disclosure&&S.push(s(le,k.dim)),S.push(A,...L,O),S.join(`
|
|
3
|
+
`)+`
|
|
4
|
+
`}function X(e){return e!==void 0&&e!==""}function Y(e=process.env,t=!!process.stdout.isTTY){if(!t)return "none";let n=e.TERM??"";if(X(e.TMUX)||n.startsWith("tmux")||n.startsWith("screen"))return "none";let r=e.TERM_PROGRAM??"";return r==="iTerm.app"||e.LC_TERMINAL==="iTerm2"||r==="WezTerm"?"iterm2":n==="xterm-kitty"||X(e.KITTY_WINDOW_ID)?"kitty":"none"}var w="\x1B",fe="\x07",me=2e3,ge=2*1024*1024,ye=new Set(["image/png","image/jpeg","image/gif","image/webp"]),v=4096;async function Se(e,t=fetch,n={}){let r=n.timeoutMs??me,o=n.maxBytes??ge;try{let i=await t(e,{signal:AbortSignal.timeout(r)});if(!i.ok)return l(`media: HTTP ${i.status} for ${e}`),null;let a=(i.headers.get("content-type")??"").split(";")[0].trim().toLowerCase();if(!ye.has(a))return l(`media: disallowed content-type "${a}" for ${e}`),null;let s=Number(i.headers.get("content-length")??"0");if(Number.isFinite(s)&&s>o)return l(`media: content-length ${s} exceeds ${o} for ${e}`),null;let u=i.body;if(u&&typeof u.getReader=="function"){let p=u.getReader(),A=[],O=0;for(;;){let{done:L,value:S}=await p.read();if(L)break;if(S!==void 0){if(O+=S.byteLength,O>o)return await p.cancel().catch(()=>{}),l(`media: stream exceeded ${o} bytes for ${e}`),null;A.push(S);}}return Buffer.concat(A)}let c=Buffer.from(await i.arrayBuffer());return c.byteLength>o?(l(`media: body ${c.byteLength} bytes exceeds ${o} for ${e}`),null):c}catch(i){return l(`media: fetch failed for ${e}:`,i),null}}function he(e){let t=e.toString("base64");return `${w}]1337;File=inline=1;size=${e.byteLength};width=auto:${t}${fe}`}function be(e){let t=e.toString("base64");if(t.length<=v)return `${w}_Gf=100,a=T;${t}${w}\\`;let n=[];for(let r=0;r<t.length;r+=v){let o=t.slice(r,r+v),a=`m=${r+v>=t.length?0:1}`,s=r===0?`f=100,a=T,${a}`:a;n.push(`${w}_G${s};${o}${w}\\`);}return n.join("")}function _(e){let t=x(e),n=e.creative;switch(n.format){case "image":case "gif":return {...t,body:n.textFallback??t.body};case "video":return {...t,body:n.textFallback??t.body,cta:t.cta??"\u25B6 Watch"};case "audio":return {...t,body:n.textFallback??t.body,cta:t.cta??"\u{1F50A} Listen"};default:return t}}async function H(e,t={}){try{let n=e.creative;if(n.format!=="image"&&n.format!=="gif")return m(_(e),t);let r=t.protocol??Y();if(r==="none"||n.mediaUrl===void 0||n.mediaUrl==="")return m(_(e),t);let o={};t.timeoutMs!==void 0&&(o.timeoutMs=t.timeoutMs),t.maxBytes!==void 0&&(o.maxBytes=t.maxBytes);let i=await Se(n.mediaUrl,t.fetchImpl??fetch,o);return i===null||i.byteLength===0?m(_(e),t):(r==="kitty"?be(i):he(i))+`
|
|
5
|
+
`+m(x(e),t)}catch(n){return l("media: render failed, falling back to text:",n),m(x(e),t)}}function Ce(e,t){return e.filter(n=>n.renderBy>t)}function Z(e,t,n=18e5){return e.filter(r=>r&&typeof r.impressionId=="string"&&typeof r.clickUrl=="string"&&r.creative&&typeof r.creative.title=="string").map(r=>({ad:r,renderBy:t+n}))}function Q(e,t){let n=Ce(e.pool,t),r=n.shift();return {ad:r?r.ad:null,pool:n}}function we(e=process.env){let t=e.XDG_CONFIG_HOME,n=t&&t.trim()!==""?t:b.join(ee.homedir(),".config");return b.join(n,"opencrater")}function te(e=process.env){return b.join(we(e),"state.json")}function ne(){return {installId:randomUUID(),lastShownAt:0,optOut:false,disclosureShown:false,cachedConfig:null,configFetchedAt:0,pool:[],allowedPlacements:{},sessionTopics:[],integrations:[]}}function y(e){return typeof e=="number"&&Number.isFinite(e)}function Ie(e){if(typeof e!="object"||e===null)return null;let t=e;return !y(t.minIntervalSeconds)||!y(t.serveTimeoutMs)||!y(t.preloadPoolSize)||typeof t.killSwitch!="boolean"?null:{minIntervalSeconds:t.minIntervalSeconds,serveTimeoutMs:t.serveTimeoutMs,preloadPoolSize:t.preloadPoolSize,killSwitch:t.killSwitch,displayDurationSeconds:y(t.displayDurationSeconds)?t.displayDurationSeconds:25,minSdkVersion:typeof t.minSdkVersion=="string"?t.minSdkVersion:""}}function Te(e){if(!Array.isArray(e))return [];let t=[];for(let n of e){if(typeof n!="object"||n===null)continue;let r=n,o=r.ad;if(!y(r.renderBy)||typeof o!="object"||o===null||typeof o.impressionId!="string"||typeof o.clickUrl!="string"||typeof o.sponsorLabel!="string"||typeof o.creative!="object"||o.creative===null)continue;let i=o.creative;typeof i.title!="string"||typeof i.body!="string"||t.push({ad:{impressionId:o.impressionId,...typeof o.campaignId=="string"?{campaignId:o.campaignId}:{},clickUrl:o.clickUrl,sponsorLabel:o.sponsorLabel,creative:{format:"text",title:i.title,body:i.body,...typeof i.cta=="string"?{cta:i.cta}:{}}},renderBy:r.renderBy});}return t}function Ae(e){if(typeof e!="object"||e===null||Array.isArray(e))return {};let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r))continue;let o=r.filter(i=>typeof i=="string"&&i.length<=64);t[n]=o.slice(0,64);}return t}function Oe(e){if(!Array.isArray(e))return [];let t=[];for(let n of e){if(typeof n!="object"||n===null)continue;let r=n;if(!(typeof r.topic!="string"||!y(r.at))&&(t.push({topic:r.topic.slice(0,32),at:r.at}),t.length>=24))break}return t}function Ee(e){if(!Array.isArray(e))return [];let t=[],n=new Set;for(let r of e){if(typeof r!="object"||r===null)continue;let o=r;if(typeof o.key!="string"||typeof o.package!="string"||o.key===""||o.package==="")continue;let i=`${o.package}\0${o.key}`;if(!n.has(i)&&(n.add(i),t.push({key:o.key,package:o.package}),t.length>=32))break}return t}function Re(e){let t=ne();if(typeof e!="object"||e===null)return t;let n=e;return {installId:typeof n.installId=="string"&&n.installId.length>0?n.installId:t.installId,lastShownAt:y(n.lastShownAt)&&n.lastShownAt>=0?n.lastShownAt:0,optOut:n.optOut===true,disclosureShown:n.disclosureShown===true,cachedConfig:Ie(n.cachedConfig),allowedPlacements:Ae(n.allowedPlacements),sessionTopics:Oe(n.sessionTopics),integrations:Ee(n.integrations),configFetchedAt:y(n.configFetchedAt)&&n.configFetchedAt>=0?n.configFetchedAt:0,pool:Te(n.pool)}}function I(e=process.env){let t=te(e);try{let n=d.readFileSync(t,"utf8"),r=JSON.parse(n);return Re(r)}catch{let n=ne();try{g(n,e);}catch{}return n}}function g(e,t=process.env){let n=te(t),r=b.dirname(n);d.mkdirSync(r,{recursive:true});let o=b.join(r,`.state.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);d.writeFileSync(o,JSON.stringify(e,null,2)+`
|
|
6
|
+
`,"utf8");let i=new Set(["EPERM","EACCES","EBUSY","EEXIST"]);for(let a=0;;a++)try{d.renameSync(o,n);return}catch(s){let u=s.code??"";if(a>=4||!i.has(u)){try{d.rmSync(o,{force:!0});}catch{}if(a>=4)return;throw s}try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,15*(a+1));}catch{}}}var Pe=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTIONS","GITLAB_CI","CIRCLECI","TRAVIS","BUILDKITE","JENKINS_URL","TEAMCITY_VERSION","TF_BUILD","APPVEYOR","CODEBUILD_BUILD_ID","DRONE","NETLIFY","VERCEL"];function G(e){return e!==void 0&&e!==""&&e!=="0"&&e.toLowerCase()!=="false"}function xe(e){return G(e.OPENCRATER_DISABLE)||G(e.TSN_DISABLE)}function ve(e){return Pe.some(t=>G(e[t]))}function V(e){return e?{...C,...e}:C}function T(e,t={}){if(xe(e.env))return "env_disabled";if(e.state.optOut)return "opt_out";let n=V(e.state.cachedConfig);if(n.killSwitch)return "kill_switch";if(ve(e.env))return "ci";if(!t.skipTTY&&!e.isTTY)return "not_tty";if(!t.skipFrequency){let r=n.minIntervalSeconds*1e3;if(e.state.lastShownAt>0&&e.now-e.state.lastShownAt<r)return "frequency"}return null}async function $(e){try{return await e()}catch(t){return l("suppressed error:",t),null}}function F(e,t){let n=V(t.cachedConfig);return {origin:z(e.apiOrigin),timeoutMs:n.serveTimeoutMs,installId:t.installId,config:n}}function _e(e,t){let n=!t.disclosureShown,r=m(e,{width:process.stdout.columns??80,color:P(),hyperlinks:R(),disclosure:n});return process.stdout.write(r),{...t,lastShownAt:Date.now(),disclosureShown:true}}async function oe(e,t){let n=await H(e,{width:process.stdout.columns??80,color:P(),hyperlinks:R(),disclosure:!t.disclosureShown});return process.stdout.write(n),{...t,lastShownAt:Date.now(),disclosureShown:true}}async function $e(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()},{skipFrequency:true});if(n!==null)return l("fetch suppressed:",n),null;let r=F(e,t),o=await j(e,r);return o?(g({...t,cachedConfig:o.config,configFetchedAt:Date.now()}),o.fill&&o.ad?o.ad:null):null}async function Fe(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()});if(n!==null)return l("suppressed:",n),false;let r=F(e,t),o=await j(e,r);return o?(t={...t,cachedConfig:o.config,configFetchedAt:Date.now()},o.fill&&o.ad?(t=await oe(o.ad,t),g(t),U(o.ad.impressionId,r),true):o.fallback?(t=_e(J(o.fallback),t),g(t),true):(g(t),false)):false}async function Le(e){let t=I(),n=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:Date.now()},{skipTTY:true,skipFrequency:true});if(n!==null)return l("preload suppressed:",n),0;let r=F(e,t),o=Math.max(1,r.config.preloadPoolSize),i=await q(e,o,r);if(!i)return 0;let a=Date.now(),s=Z(i.ads,a);return g({...t,pool:s,cachedConfig:i.config,configFetchedAt:a}),s.length}async function Me(e){let t=I(),n=Date.now(),r=T({env:process.env,isTTY:!!process.stdout.isTTY,state:t,now:n});if(r!==null)return l("renderFromPool suppressed:",r),false;let{ad:o,pool:i}=Q(t,n);if(!o)return g({...t,pool:i}),false;let a=await oe(o,{...t,pool:i});g(a);let s=F(e,t);return U(o.impressionId,s),true}var st={show(e){return $(()=>Fe(e)).then(t=>t??false)},fetch(e){return $(()=>$e(e))},preload(e){return $(()=>Le(e)).then(t=>t??0)},renderFromPool(e){return $(()=>Me(e)).then(t=>t??false)}};export{C as DEFAULT_CONFIG,re as HOOK_CATALOG,N as SDK_VERSION,Y as detectImageProtocol,H as renderAd,m as renderCard,st as sponsor,_ as textCardForAd};
|
package/dist/paint.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';var child_process=require('child_process'),crypto=require('crypto'),je=require('http'),rt=require('fs'),Pe=require('os'),U=require('path'),zlib=require('zlib'),pe=require('tty');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var je__namespace=/*#__PURE__*/_interopNamespace(je);var rt__namespace=/*#__PURE__*/_interopNamespace(rt);var Pe__namespace=/*#__PURE__*/_interopNamespace(Pe);var U__namespace=/*#__PURE__*/_interopNamespace(U);var pe__namespace=/*#__PURE__*/_interopNamespace(pe);var ee=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,n)=>(typeof require<"u"?require:e)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});function Ae(t){return t>=21||t<8?.2:.4}function Ce(t,e){let n=e.filter(i=>Number.isFinite(i)&&t-i<6e5&&i<=t);return n.length>=2?{play:false,next:n}:{play:true,next:[...n,t]}}function ne(t=process.env){let e=t.XDG_CONFIG_HOME,n=e&&e.trim()!==""?e:U__namespace.join(Pe__namespace.homedir(),".config");return U__namespace.join(n,"opencrater")}var an=600*1e3;function re(){return U__namespace.join(ne(),"blocked-ads.json")}function oe(){return U__namespace.join(ne(),"reported-ads.json")}function cn(t,e){let n={};for(let[i,s]of Object.entries(t))typeof s=="number"&&Number.isFinite(s)&&s>e&&(n[i]=s);return n}function ln(t){try{let e=JSON.parse(rt__namespace.readFileSync(re(),"utf8"));return cn(e&&typeof e=="object"?e:{},t)}catch{return {}}}function Lt(t,e=Date.now()){if(t)try{let n=ln(e);n[t]=e+an,rt__namespace.mkdirSync(U__namespace.dirname(re()),{recursive:!0}),rt__namespace.writeFileSync(re(),JSON.stringify(n));}catch{}}function un(){try{let t=JSON.parse(rt__namespace.readFileSync(oe(),"utf8"));return t&&typeof t=="object"?t:{}}catch{return {}}}function Re(t,e=Date.now()){if(t)try{let n=un();n[t]=e,rt__namespace.mkdirSync(U__namespace.dirname(oe()),{recursive:!0}),rt__namespace.writeFileSync(oe(),JSON.stringify(n));}catch{}}var fn=[137,80,78,71,13,10,26,10];function ke(t){try{if(t.length<45)return null;for(let P=0;P<8;P++)if(t[P]!==fn[P])return null;let e=new DataView(t.buffer,t.byteOffset,t.byteLength),n=8,i=0,s=0,p=0,o=-1,d=0,f=[];for(;n+8<=t.length;){let P=e.getUint32(n),D=String.fromCharCode(t[n+4],t[n+5],t[n+6],t[n+7]),W=t.subarray(n+8,n+8+P);if(D==="IHDR")i=e.getUint32(n+8),s=e.getUint32(n+12),p=t[n+16],o=t[n+17],d=t[n+20];else if(D==="IDAT")f.push(W);else if(D==="IEND")break;n+=12+P;}if(p!==8||o!==2&&o!==6||d!==0||i===0||s===0||i>1024||s>1024)return null;let $=o===6?4:3,h=i*$,l=zlib.inflateSync(Buffer.concat(f.map(P=>Buffer.from(P))));if(l.length<(h+1)*s)return null;let _=new Uint8Array(i*s*4),I=new Uint8Array(h),O=new Uint8Array(h);for(let P=0;P<s;P++){let D=P*(h+1),W=l[D];for(let M=0;M<h;M++){let x=l[D+1+M],b=M>=$?O[M-$]:0,v=I[M],j=M>=$?I[M-$]:0,y;switch(W){case 0:y=x;break;case 1:y=x+b;break;case 2:y=x+v;break;case 3:y=x+(b+v>>1);break;case 4:{let E=b+v-j,X=Math.abs(E-b),Ot=Math.abs(E-v),B=Math.abs(E-j);y=x+(X<=Ot&&X<=B?b:Ot<=B?v:j);break}default:return null}O[M]=y&255;}for(let M=0;M<i;M++){let x=M*$,b=(P*i+M)*4;_[b]=O[x],_[b+1]=O[x+1],_[b+2]=O[x+2],_[b+3]=$===4?O[x+3]:255;}I.set(O);}return {width:i,height:s,rgba:_}}catch{return null}}var Ut=300,Ne=140,se=12e3,Sn=9;var vn=1500,_e=3*1024*1024,In=12*1024*1024,On=12*1024*1024,xn=6e3,Ee=25e3,Ge=64,S="\x1B",Mn="\x07",Te=`${S}7`,De=`${S}8`;function Ft(t,e){return `${S}]8;;${t}${S}\\${e}${S}]8;;${S}\\`}function Wt(t){return t.replace(/\x1b\[[0-9;]*m/g,"").replace(/\x1b\]8;;[^\x1b\x07]*(?:\x1b\\|\x07)/g,"").replace(/[︎️]/g,"").length}function mt(t,e){return t.length<=e?t:`${t.slice(0,Math.max(0,e-1))}\u2026`}function An(t,e){let n=t.split(/\s+/).filter(Boolean),i=[],s="";for(let p of n)if(s===""?s=mt(p,e):s.length+1+p.length<=e?s+=` ${p}`:(i.push(s),s=mt(p,e)),i.length>=3)break;return s&&i.length<4&&i.push(s),i}var Y=process.platform==="win32";function ot(t){return Y?`${t}\uFE0E`:t}function Cn(t){let e=()=>{try{rt.closeSync(t);}catch{}};return {write:n=>{try{rt.writeSync(t,n);}catch{}},close:e,closeAndWait:async()=>e()}}var Pn=["$ErrorActionPreference='SilentlyContinue'","$dbg=$env:OPENCRATER_DEBUG -eq '1'","$log=Join-Path $env:USERPROFILE '.config\\opencrater\\pump.log'","function L($m){ if($dbg){ try{ Add-Content -LiteralPath $log -Value ((Get-Date).ToString('o')+' '+$m) }catch{} } }","L 'pump: process started (loading types)'","Add-Type -TypeDefinition @'","using System;using System.Runtime.InteropServices;","namespace OCP{","public struct COORD{public short X;public short Y;}","public struct SR{public short L;public short T;public short R;public short B;}","public struct CSBI{public COORD sz;public COORD cur;public ushort attr;public SR win;public COORD max;}","public static class N{",'[DllImport("kernel32.dll",SetLastError=true,CharSet=CharSet.Unicode)]public static extern IntPtr CreateFileW(string n,uint a,uint s,IntPtr sec,uint d,uint f,IntPtr t);','[DllImport("kernel32.dll")]public static extern bool GetConsoleMode(IntPtr h,out uint m);','[DllImport("kernel32.dll")]public static extern bool SetConsoleMode(IntPtr h,uint m);','[DllImport("kernel32.dll")]public static extern bool SetConsoleOutputCP(uint cp);','[DllImport("kernel32.dll")]public static extern bool WriteFile(IntPtr h,byte[] b,uint n,out uint w,IntPtr o);','[DllImport("kernel32.dll")]public static extern bool FreeConsole();','[DllImport("kernel32.dll")]public static extern bool AttachConsole(uint p);','[DllImport("kernel32.dll")]public static extern IntPtr GetStdHandle(int n);','[DllImport("kernel32.dll")]public static extern bool GetConsoleScreenBufferInfo(IntPtr h,out CSBI i);',"}}","'@","L 'pump: types loaded'","$o=[uint32]'0xC0000000'","function OpenConout(){ return [OCP.N]::CreateFileW('CONOUT$',$o,3,[IntPtr]::Zero,3,0,[IntPtr]::Zero) }","function Csbi($hh){ $z=New-Object OCP.CSBI; if($hh -ne [IntPtr]-1 -and [OCP.N]::GetConsoleScreenBufferInfo($hh,[ref]$z)){ return $z } else { return $null } }","$self=Csbi (OpenConout); if($self){ L ('pump: SELF bufH='+$self.sz.Y+' winRows='+($self.win.B-$self.win.T+1)+' curY='+$self.cur.Y) }","$how='self'; $winId=0","$given=[int]($env:OPENCRATER_WIN_CONSOLE_PID)","if($given -gt 0){ [void][OCP.N]::FreeConsole(); if([OCP.N]::AttachConsole([uint32]$given)){ $winId=$given; $how='given' } L ('pump: given console pid '+$given+' attached='+($winId -eq $given)) }","if($winId -eq 0){"," $par=@{}; try{ Get-CimInstance Win32_Process -ErrorAction Stop | ForEach-Object { $par[[int]$_.ProcessId]=[int]$_.ParentProcessId } }catch{ L 'pump: WMI walk failed' }"," $chain=New-Object System.Collections.ArrayList; $p=$PID; for($i=0;$i -lt 12;$i++){ if(-not $par.ContainsKey($p)){break}; $pp=$par[$p]; if($pp -le 4){break}; $nm='?'; try{ $nm=(Get-Process -Id $pp -ErrorAction Stop).ProcessName }catch{}; [void]$chain.Add(@{id=$pp;name=$nm}); $p=$pp }"," L ('pump: ancestors = ' + (($chain | ForEach-Object { $_.name+'('+$_.id+')' }) -join ' -> '))"," foreach($c in $chain){ [void][OCP.N]::FreeConsole(); if([OCP.N]::AttachConsole([uint32]$c.id)){ $b=Csbi (OpenConout); if($b){ L ('pump: '+$c.name+'('+$c.id+') bufH='+$b.sz.Y+' winRows='+($b.win.B-$b.win.T+1)+' curY='+$b.cur.Y); if($winId -eq 0 -and $b.sz.Y -lt 1000){ $winId=$c.id; $how=('attach:'+$c.name) } } } }","}","[void][OCP.N]::FreeConsole()","if($winId -ne 0){ [void][OCP.N]::AttachConsole([uint32]$winId) } else { [void][OCP.N]::AttachConsole(0xFFFFFFFF); $how='attach-parent' }","$h=OpenConout","if($h -eq [IntPtr]-1){ L 'pump: NO CONSOLE after attach walk'; exit 1 }","$fb=Csbi $h; if($fb){ L ('pump: FINAL via '+$how+' bufH='+$fb.sz.Y+' winRows='+($fb.win.B-$fb.win.T+1)+' curY='+$fb.cur.Y) } else { L ('pump: FINAL via '+$how) }","if($fb){ $cols=$fb.win.R-$fb.win.L+1; $rows=$fb.win.B-$fb.win.T+1; [Console]::Out.WriteLine('OCWIN '+$winId+' '+$cols+' '+$rows); [Console]::Out.Flush() }","$m=[uint32]0;[void][OCP.N]::GetConsoleMode($h,[ref]$m);[void][OCP.N]::SetConsoleMode($h,($m -bor 4));[void][OCP.N]::SetConsoleOutputCP(65001)","$in=[Console]::OpenStandardInput();$buf=New-Object byte[] 65536;$tot=0;$frames=0","while(($n=$in.Read($buf,0,$buf.Length)) -gt 0){$w=[uint32]0;[void][OCP.N]::WriteFile($h,$buf,$n,[ref]$w,[IntPtr]::Zero);$tot+=$w;$frames++}","L ('pump: stdin closed, streamed '+$tot+' bytes in '+$frames+' chunks')"].join(`
|
|
3
|
+
`);function He(){return `${process.env.SystemRoot||process.env.windir||"C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`}function Rn(){try{let t=Buffer.from(Pn,"utf16le").toString("base64"),e=He(),n="ignore";if(process.env.OPENCRATER_DEBUG==="1")try{n=rt.openSync(U__namespace.join(Pe.homedir(),".config","opencrater","pump-err.log"),"a");}catch{}T("spawning pump:",e);let i=child_process.spawn(e,["-NoProfile","-NonInteractive","-EncodedCommand",t],{stdio:["pipe","pipe",n],windowsHide:!0});i.on("error",d=>T("pump spawn error:",e,"-",d.message)),i.on("exit",d=>T("pump process exited code",d,"pid",i.pid));let s=i.stdin;if(!s)return T("pump: no stdin pipe"),null;s.on("error",()=>{});let p=!1;return i.on("exit",()=>{p=!0;}),{size:new Promise(d=>{let f="",$=!1,h=_=>{$||($=!0,d(_));},l=i.stdout;if(!l)return h(null);l.setEncoding("utf8"),l.on("data",_=>{f+=_;let I=f.match(/OCWIN\s+(\d+)\s+(\d+)\s+(\d+)/);I&&(T("pump reported console pid",I[1],"size",I[2]+"x"+I[3]),h({pid:Number(I[1]),cols:Number(I[2]),rows:Number(I[3])}));}),l.on("error",()=>h(null)),l.on("end",()=>h(null)),setTimeout(()=>h(null),2500);}),write:d=>{try{s.write(d);}catch{}},close:()=>{try{s.end();}catch{}},closeAndWait:()=>new Promise(d=>{if(p)return d();let f=!1,$=()=>{f||(f=!0,d());};i.on("exit",$),setTimeout($,5e3);try{s.end();}catch{$();}})}}catch(t){return T("pump: spawn threw",t.message),null}}function kn(t){try{let e=t.replace(/'/g,"''"),n=`$ErrorActionPreference='Stop';try{$r=$null;try{$su=([wmiclass]'Win32_ProcessStartup').CreateInstance();$su.CreateFlags=[uint32]8;$r=([wmiclass]'Win32_Process').Create('${e}',$null,$su)}catch{};if($r -eq $null -or $r.ReturnValue -ne 0){$r=([wmiclass]'Win32_Process').Create('${e}')};if($r.ReturnValue -eq 0){[Console]::Out.Write('OCPID '+$r.ProcessId)}else{[Console]::Out.Write('OCERR rv='+$r.ReturnValue)}}catch{[Console]::Out.Write('OCERR '+$_.Exception.Message)}`,i=Buffer.from(n,"utf16le").toString("base64"),s=child_process.spawnSync(He(),["-NoProfile","-NonInteractive","-EncodedCommand",i],{timeout:5e3,encoding:"utf8"}),p=(s.stdout??"").match(/OCPID\s+(\d+)/);return p?Number(p[1]):(T("wmi spawn failed:",(s.stdout??"").trim(),"|",(s.stderr??"").trim()),0)}catch(e){return T("wmi spawn threw",e.message),0}}function Nn(t,e){try{let n=U__namespace.join(Pe.homedir(),".config","opencrater");rt.mkdirSync(n,{recursive:!0});let i=U__namespace.join(n,`paint-${process.pid}-${Date.now()}.json`);rt.writeFileSync(i,JSON.stringify({...t,_env:process.env}),"utf8");let s=d=>`"${d}"`,p=[s(process.execPath),s(__filename),"--persist","--payload-file",s(i),"--console-pid",String(e)];jt&&p.push("--debug");let o=kn(p.join(" "));return T("escape: wmi persistent painter pid",o),o>0}catch(n){return T("escape failed",n.message),false}}function cr(t){return !!(t.WT_SESSION||t.TERM_PROGRAM||t.ConEmuANSI==="ON"||t.ANSICON)}function _n(){try{let t=child_process.spawnSync("mode",["con"],{timeout:1500,encoding:"utf8"}).stdout;if(!t)return null;let n=[...t.matchAll(/:\s*(\d+)/g)].map(i=>Number(i[1]))[1];return n&&n>0?n:null}catch{return null}}function En(t){let e=t.TERM_PROGRAM??"",n=t.TERM??"";return t.TMUX?"none":e==="iTerm.app"||t.LC_TERMINAL==="iTerm2"||e==="WezTerm"?"iterm2":n==="xterm-kitty"||t.KITTY_WINDOW_ID?"kitty":"none"}function Le(t,e){let n=t.toString("base64");return `${S}]1337;File=inline=1;size=${t.length};width=${e.w};height=${e.h};preserveAspectRatio=1:${n}${Mn}`}function Tn(t,e){let n=t.toString("base64"),i=[];for(let p=0;p<n.length;p+=4096)i.push(n.slice(p,p+4096));let s="";for(let p=0;p<i.length;p++){let o=p===0,d=p===i.length-1,f=o?`a=T,f=100,c=${e.w},r=${e.h},m=${d?0:1}`:`m=${d?0:1}`;s+=`${S}_G${f};${i[p]}${S}\\`;}return s}function Dn(t){let e=(t.COLORTERM??"").toLowerCase();if(e.includes("truecolor")||e.includes("24bit"))return true;let n=t.TERM_PROGRAM??"";return ["iTerm.app","WezTerm","vscode","ghostty","Apple_Terminal"].includes(n)}function ae(t,e,n){if(Math.abs(t-e)<12&&Math.abs(e-n)<12&&Math.abs(t-n)<12)return t<8?16:t>248?231:232+Math.round((t-8)/247*23);let i=s=>Math.round(s/255*5);return 16+36*i(t)+6*i(e)+i(n)}var Ln=[" ","\u2598","\u259D","\u2580","\u2596","\u258C","\u259E","\u259B","\u2597","\u259A","\u2590","\u259C","\u2584","\u2599","\u259F","\u2588"];function ze(t,e,n,i){let s=[],p=(d,f)=>{let $=(f*e+d)*3;return [t[$],t[$+1],t[$+2]]},o=(d,f)=>{let $=d[0]-f[0],h=d[1]-f[1],l=d[2]-f[2];return $*$+h*h+l*l};for(let d=0;d+1<n;d+=2){let f="",$="";for(let h=0;h+1<e;h+=2){let l=[p(h,d),p(h+1,d),p(h,d+1),p(h+1,d+1)],_=0,I=1,O=-1;for(let y=0;y<4;y++)for(let E=y+1;E<4;E++){let X=o(l[y],l[E]);X>O&&(O=X,_=y,I=E);}let P=0,D=[0,0,0],W=[0,0,0],M=0,x=0;for(let y=0;y<4;y++)o(l[y],l[_])<=o(l[y],l[I])?(P|=1<<y,D[0]+=l[y][0],D[1]+=l[y][1],D[2]+=l[y][2],M++):(W[0]+=l[y][0],W[1]+=l[y][1],W[2]+=l[y][2],x++);if(O<1e3){let y=Ot=>Ot&-8,E=[y(Math.round((l[0][0]+l[1][0]+l[2][0]+l[3][0])/4)),y(Math.round((l[0][1]+l[1][1]+l[2][1]+l[3][1])/4)),y(Math.round((l[0][2]+l[1][2]+l[2][2]+l[3][2])/4))],X=i?`${S}[48;2;${E[0]};${E[1]};${E[2]}m`:`${S}[48;5;${ae(E[0],E[1],E[2])}m`;X!==$&&(f+=X,$=X),f+=" ";continue}let b=M?[Math.round(D[0]/M),Math.round(D[1]/M),Math.round(D[2]/M)]:[0,0,0],v=x?[Math.round(W[0]/x),Math.round(W[1]/x),Math.round(W[2]/x)]:b,j=i?`${S}[38;2;${b[0]};${b[1]};${b[2]};48;2;${v[0]};${v[1]};${v[2]}m`:`${S}[38;5;${ae(b[0],b[1],b[2])};48;5;${ae(v[0],v[1],v[2])}m`;j!==$&&(f+=j,$=j),f+=Ln[P];}f+=`${S}[0m`,s.push(f);}return s}function Un(t,e,n,i,s,p){let o=e*2,d=n*2,f=`${p?`${p},`:""}scale=${o}:${d}:flags=lanczos+accurate_rnd`,$=["-y","-i",t];i?$.push("-t","6","-vf",`fps=7,${f}`):$.push("-frames:v","1","-vf",f),$.push("-f","rawvideo","-pix_fmt","rgb24","-");let h=child_process.spawnSync("ffmpeg",$,{timeout:12e3,maxBuffer:64*1024*1024});if(h.status!==0||!h.stdout||h.stdout.length===0)return null;let l=o*d*3,_=Math.min(Math.floor(h.stdout.length/l),Ge);if(_===0)return null;let I=[];for(let O=0;O<_;O++)I.push(ze(h.stdout.subarray(O*l,(O+1)*l),o,d,s));return I}function Fn(t,e,n,i,s,p){if(!tt("chafa"))return null;let o=U__namespace.join(e,"fr_%03d.png"),d=["-y","-i",t],f=[];if(s?(d.push("-t","6"),f.push("fps=5")):d.push("-frames:v","1"),p&&f.push(p),f.length>0&&d.push("-vf",f.join(",")),d.push(o),child_process.spawnSync("ffmpeg",d,{timeout:12e3}).status!==0)return null;let h=[];for(let l=1;l<=Ge;l++){let _=U__namespace.join(e,`fr_${String(l).padStart(3,"0")}.png`),I;try{I=child_process.spawnSync("chafa",s?["-f","symbols","-s",`${n}x${i}`,"--stretch","--symbols","vhalf","--colors","full",_]:["-f","symbols","-s",`${n}x${i}`,"--stretch","--colors","full",_],{timeout:5e3,maxBuffer:8*1024*1024,encoding:"utf8"});}catch{break}if(I.status!==0||!I.stdout)break;let P=I.stdout.replace(/\x1b\[\?25[lh]/g,"").split(`
|
|
4
|
+
`).filter(x=>x.length>0);if(P.length===0)break;let D=" ".repeat(n),W=Math.floor((i-P.length)/2),M=[];for(let x=0;x<i;x++){let b=P[x-W];if(b===void 0)M.push(D);else {let v=" ".repeat(Math.max(0,n-Wt(b)));M.push(b+v);}}h.push(M);}return h.length>0?h:null}function Je(t){try{let e=child_process.spawnSync("ffprobe",["-v","quiet","-select_streams","v:0","-show_entries","stream=width,height","-of","csv=p=0",t],{timeout:5e3,encoding:"utf8"});if(e.status!==0||!e.stdout)return null;let n=e.stdout.trim().match(/^(\d+),(\d+)/);if(!n)return null;let i=Number(n[1]),s=Number(n[2]);return i>0&&s>0?{w:i,h:s}:null}catch{return null}}function Wn(t){try{let n=(child_process.spawnSync("ffmpeg",["-t","2","-i",t,"-vf","cropdetect=24:2:1","-f","null","-"],{timeout:8e3,encoding:"utf8"}).stderr??"").match(/crop=(\d+):(\d+):(\d+):(\d+)/g);if(!n||n.length===0)return null;let i=n[n.length-1],s=i.match(/crop=(\d+):(\d+):(\d+):(\d+)/),p=Number(s[1]),o=Number(s[2]);if(p<8||o<8)return null;let d=Je(t);if(d){let f=p*o/(d.w*d.h);if(f<.55||f>.92)return null}return i}catch{return null}}function tt(t){try{return Y?child_process.spawnSync("where",[t],{timeout:2e3}).status===0:child_process.spawnSync("sh",["-c",'command -v -- "$1" >/dev/null 2>&1',"sh",t],{timeout:2e3}).status===0}catch{return false}}async function Ue(t,e){try{let n=await fetch(t,{signal:AbortSignal.timeout(xn)});if(!n.ok)return null;let i=(n.headers.get("content-type")??"").split(";")[0].trim().toLowerCase();if(Number(n.headers.get("content-length")??"0")>e)return null;let p=Buffer.from(await n.arrayBuffer());return p.length===0||p.length>e?null:{data:p,type:i}}catch{return null}}var It=U__namespace.join(Pe.homedir(),".config","opencrater","painter.lock"),jn=6e3;function Fe(t){try{if(!rt.existsSync(It))return;let e=JSON.parse(rt.readFileSync(It,"utf8"));if(e.pid&&e.pid!==process.pid){if(e.startedAt&&Date.now()-e.startedAt<jn){let i=!0;try{process.kill(e.pid,0);}catch{i=!1;}i&&(t.close(),process.exit(0));}let n=!0;try{process.kill(e.pid,"SIGTERM");}catch{n=!1;}try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,250);}catch{}if(e.rows>0&&e.width>0){let i="\x1B7\x1B[0m",s=" ".repeat(e.width);for(let p=0;p<e.rows;p++)i+=`\x1B[${e.row+p};${e.col}H${s}`;i+="\x1B8",t.write(i);}}}catch{}}var We="";function Bn(t){let e=JSON.stringify(t);if(e!==We){We=e;try{rt.mkdirSync(U__namespace.dirname(It),{recursive:!0}),rt.writeFileSync(It,JSON.stringify(t));}catch{}}}function Gn(){try{JSON.parse(rt.readFileSync(It,"utf8")).pid===process.pid&&rt.unlinkSync(It);}catch{}}var jt=process.env.OPENCRATER_DEBUG==="1";function T(...t){try{if(!jt)return;let e=`[opencrater-paint] ${t.map(n=>String(n)).join(" ")}`;console.error(e);try{rt.appendFileSync(U__namespace.join(Pe.homedir(),".config","opencrater","paint.log"),`${new Date().toISOString()} ${e}
|
|
5
|
+
`);}catch{}}catch{}}function Hn(){let t=process.argv.slice(2),e=r=>{let a=t.indexOf(r);return a>=0?t[a+1]:void 0};t.includes("--debug")&&(jt=true,process.env.OPENCRATER_DEBUG="1");let n=t.includes("--persist")||process.env.OPENCRATER_WIN_PERSIST==="1",i=Number(e("--console-pid")??"0");i>0&&(process.env.OPENCRATER_WIN_CONSOLE_PID=String(i));let s=e("--payload-file"),p=process.env.OPENCRATER_PAINT;if(s)try{p=rt.readFileSync(s,"utf8");}catch(r){T("payload-file unreadable:",r.message);}if(!p){T("no paint payload (env or --payload-file) \u2014 nothing to draw");return}let o;try{let r=JSON.parse(p);if(r._env&&typeof r._env=="object"){let a=process.env.OPENCRATER_WIN_CONSOLE_PID;Object.assign(process.env,r._env),a&&(process.env.OPENCRATER_WIN_CONSOLE_PID=a),process.env.OPENCRATER_DEBUG==="1"&&(jt=!0),delete r._env;}o=r;}catch(r){T("paint payload is not valid JSON:",r.message);return}let d=process.env.OPENCRATER_TTY??"/dev/tty",f,$=-1;if(Y){let r=Rn();if(!r){T("Windows: could not start the console pump (powershell.exe)");return}f=r;}else {try{$=rt.openSync(d,"w");}catch(r){T("could not open output device",d,"-",r.message);return}f=Cn($);}T("painting via",Y?"Windows console pump":d,"format",o.format??"text"),process.env.OPENCRATER_FLOW!=="1"&&!Y&&Fe(f);let h=0;if(Y)h=_n()??0;else try{let r=new pe__namespace.WriteStream($);r.columns&&(h=r.columns);}catch{}h||(h=80);let l=process.env.NO_COLOR===void 0,_=l&&Dn(process.env),I=(o.format??"text").toLowerCase(),O=I==="image"||I==="logo",P=I==="gif"||I==="video",D=P?72:56,W=Y?24:40;if(Y)process.stdout.rows&&(W=process.stdout.rows);else try{let r=new pe__namespace.WriteStream(rt.openSync(d,"w"));r.rows&&(W=r.rows);}catch{}let M=P?Math.max(8,Math.min(16,Math.floor((W-14)/2)*2)):Sn,x=O?5:M,b=Math.min(D,h-4);if(b<24){f.close();return}let v=b-4,j=Math.max(1,h-b-1),y=2,E=Date.now(),X=l?`${S}[2m`:"",B=l?`${S}[38;5;214m`:"",L=l?`${S}[0m`:"",k=I,xt=En(process.env),Ct=process.env.OPENCRATER_FLOW==="1",Ye=process.env.OPENCRATER_MUTE==="1",it=o.apiOrigin??"https://api.opencrater.to",Mt=k==="video"?`${ot("\u25B6")} `:k==="audio"?`${ot("\u266A")} `:"",fe=false,de=r=>{if(o.impressionId)try{fetch(`${it}/v1/events/engagement`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({impressionId:o.impressionId,events:r}),signal:AbortSignal.timeout(1500)}).catch(()=>{});}catch{}},nt=null,G=null,Pt=0,pt=0,q=null,H="none",Bt=null,Gt=null,st=null,Ht=0,me=0,Q=null,N=0,R=0,Xe=(r,a)=>{let u=r/a,c=O?Math.min(10,Math.floor(v*.35)):v;N=Math.max(4,Math.min(c,Math.round(2*u*x))),R=Math.max(2,Math.min(x,Math.round(c/(2*u))||x)),O&&(R=Math.min(R,x));let m=Math.min(1,r/(N*2),a/(R*2));m<1&&(N=Math.max(8,Math.floor(N*m)),R=Math.max(2,Math.floor(R*m)));},ht=0,qe=()=>{let r=(o.sponsorLabel??"").trim(),a=r.toLowerCase()===o.title.trim().toLowerCase(),u=r&&!a?`Sponsored \xB7 ${r}`:"Sponsored",c=[],m=gt??`${it}/x/${o.impressionId}`,g=o.impressionId||o.replay&>?Ft(m,ot("\u2715")):"",w=ht>0&&!Ct?Math.max(0,Math.ceil((ht-Date.now())/1e3)):0,z=w>0?`Auto dismiss in: ${w}s `:"",J=l?w<=5?`${S}[1;38;5;196m`:w<=12?`${S}[1;38;5;178m`:`${S}[1;38;5;35m`:"",C=mt(u,Math.max(8,v-2-z.length)),A=" ".repeat(Math.max(1,v-C.length-z.length-1));c.push(`${X}${C}${L}${A}${J}${z}${L}${B}${g}${L}`);let F=l?xt!=="none"||(process.env.COLORTERM??"").includes("truecolor")?`${S}[1;38;2;255;184;48m`:`${S}[1;38;5;214m`:"",Z=O&&R>0?v-N-2:v;O||c.push(""),c.push(`${F}${mt(o.title.toUpperCase(),Z)}${L}`);for(let V of An(o.body,Z))c.push(V);if(H!=="none"){let V=H==="playing"?`${ot("\u23F8")} pause`:H==="paused"?`${ot("\u25B6")} play`:`${ot("\u25B6")} replay`,ft=Math.max(6,Math.min(14,Z-V.length-5)),dt="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588",Et="";for(let Tt=0;Tt<ft;Tt++){let sn=H==="playing"?Math.abs(Math.sin(pt*.9+Tt*1.7)*.55+Math.sin(pt*.37+Tt*.53)*.45):.05;Et+=dt[Math.max(0,Math.min(7,Math.floor(sn*8)))];}let on=Bt?Ft(Bt,V):V;c.push(`${ot("\u266A")} ${B}${Et}${L} ${B}${on}${L}`);}let lt=process.env.TERM_PROGRAM??"",qt=process.env.TERM??"",Kt=xt!=="none"||["vscode","ghostty","iTerm.app","WezTerm","Hyper","WarpTerminal","rio","Tabby"].includes(lt)||/kitty|wezterm|alacritty|foot|rio|ghostty/i.test(qt)||process.env.WT_SESSION!==void 0||process.env.ConEmuANSI==="ON"||process.env.VTE_VERSION!==void 0,Zt=(V,ft,dt)=>l?`${S}[48;2;${ft[0]};${ft[1]};${ft[2]};38;2;${dt[0]};${dt[1]};${dt[2]};1m ${V} ${S}[0m`:`[ ${V} ]`,$t=[240,178,50],Qt=[12,12,10],te=o.impressionId?`${it}/k/${o.impressionId}`:o.url,yt=[];if(Kt){let V=mt(o.cta&&o.cta.trim()!==""?o.cta:"visit sponsor",v-6-Mt.length);yt.push(Ft(o.url,Zt(`${Mt}${V} \u2192`,$t,Qt)));}else {let V=(o.cta&&o.cta.trim()!==""?o.cta.trim():"VISIT").toUpperCase();Mt.length+V.length+1+te.length<=v?yt.push(Zt(`${V} ${Mt}${te}`,$t,Qt)):yt.push(Zt(`${Mt}${te}`,$t,Qt));let ft=process.platform==="darwin"?"\u2318-click":"Ctrl-click",dt=mt(`${ot("\u2191")} ${ft} the link to open`,v),Et=l?`${S}[38;2;${$t[0]};${$t[1]};${$t[2]}m`:"";yt.push(`${Et}${dt}${L}`);}let xe=Gt??(o.impressionId?`${it}/r/${o.impressionId}`:null),Me=xe&&Kt?` \xB7 ${Ft(xe,`${ot("\u2691")} report`)}`:"",rn=Kt?"dismiss: click \u2715 or npx opencrater x \xB7 opt out: npx opencrater off":"dismiss: npx opencrater x \xB7 opt out: npx opencrater off";return yt.push(`${X}${mt(rn,Math.max(0,v-Wt(Me)))}${Me}${L}`),{head:c,tail:yt}},he=0,ge=()=>{let{head:r,tail:a}=qe(),u=`${B}\u256D${"\u2500".repeat(b-2)}\u256E${L}`,c=`${B}\u2570${"\u2500".repeat(b-2)}\u256F${L}`,m=w=>{let z=" ".repeat(Math.max(0,v-Wt(w)));return `${B}\u2502${L} ${w}${z} ${B}\u2502${L}`},g;if(O&&R>0&&(G||nt)){let w=v-N-2,z=r[0]??"",J=r.slice(1),C=G?G[Pt%G.length]:null;g=[u,m(z)];let A=Math.max(J.length,R);for(let F=0;F<A;F++){let Z=J[F]??"",lt=" ".repeat(Math.max(0,w-Wt(Z))),qt=F<R&&C?C[F]??" ".repeat(N):" ".repeat(N);g.push(`${B}\u2502${L} ${Z}${lt} ${qt} ${B}\u2502${L}`);}}else {g=[u,...r.map(m)];let w=Math.max(0,Math.floor((v-N)/2)),z=Math.max(0,v-N-w);if(G&&R>0){let J=G[Pt%G.length];for(let C=0;C<R;C++){let A=J[C]??" ".repeat(N);g.push(`${B}\u2502${L} ${" ".repeat(w)}${A}${" ".repeat(z)} ${B}\u2502${L}`);}}else if(nt&&R>0)for(let J=0;J<R;J++)g.push(`${B}\u2502${L} ${" ".repeat(v)} ${B}\u2502${L}`);}return g.push(...a.map(m)),g.push(c),he=a.length+1,g},zt=0,be=`${S}[?2026h`,$e=`${S}[?2026l`,ye=0,we=2e3,Ze=8,Jt=()=>{let r=ge();zt=Math.max(zt,r.length),Bn({pid:process.pid,row:y,col:j,width:b,rows:r.length,startedAt:E,...o.impressionId?{impressionId:o.impressionId}:{},...gt?{dismissUrl:gt}:{}});let a=be+Te,u=Date.now()<ye,c=Math.max(1,y-(u?Ze:2));for(let m=c;m<y;m++)a+=`${S}[${m};${j}H${S}[0m${" ".repeat(b)}`;for(let m=0;m<r.length;m++)a+=`${S}[${y+m};${j}H${r[m]}`;if(nt&&pt%(u?1:3)===0&&R>0){let m=O?y+2:y+r.length-he-R,g=O?j+2+(v-N):j+2+Math.max(0,Math.floor((v-N)/2));a+=`${S}[${m};${g}H${nt}`;}return a+=De+$e,pt++,G&&G.length>1&&Pt++,a},at=()=>{f.write(Jt());},Se=()=>{let r=be+Te+`${S}[0m`,a=" ".repeat(b);for(let u=0;u<zt;u++)r+=`${S}[${y+u};${j}H${a}`;r+=De+$e,f.write(r);},ct=null,Rt=null,kt=null,Nt=null,gt=null,K=r=>{if(T("cleanup wipe="+r+" elapsed="+(Date.now()-E)+"ms"),fe||(fe=true,de([{type:"dwell",ms:Date.now()-E}])),ct&&clearInterval(ct),Rt&&clearInterval(Rt),kt&&clearInterval(kt),r){let a=Number(process.env.OPENCRATER_HOST_PID??0);a>1&&!Y&&setTimeout(()=>{try{process.kill(a,"SIGWINCH");}catch{}},80);}if(Nt){try{Nt.close();}catch{}Nt=null;}if(ct=null,Rt=null,kt=null,q){try{q.kill("SIGKILL");}catch{}q=null;}if(Q){try{rt.rmSync(Q,{recursive:!0,force:!0});}catch{}Q=null;}if(Se(),Gn(),Y){let a=false,u=()=>{a||(a=true,process.exit(0));};f.closeAndWait().then(u),setTimeout(u,1500).unref?.();return}f.close(),process.exit(0);},Qe=()=>{ct&&clearInterval(ct);let a=N*R>1100?200:Ne;ct=setInterval(at,G&&G.length>1?a:Ut);},_t=()=>(Q||(Q=rt.mkdtempSync(U__namespace.join(Pe.tmpdir(),"ocpaint-"))),Q),Yt=async()=>{if(o.mediaPixelUrl&&(I==="image"||I==="logo"))try{let C=await fetch(o.mediaPixelUrl,{signal:AbortSignal.timeout(2500)});if(C.ok){let A=ke(new Uint8Array(await C.arrayBuffer()));if(A&&A.width>=4&&A.height>=2){let F=Buffer.alloc(A.width*A.height*3);for(let Z=0,lt=0;Z<A.rgba.length;Z+=4,lt+=3)F[lt]=A.rgba[Z],F[lt+1]=A.rgba[Z+1],F[lt+2]=A.rgba[Z+2];N=Math.floor(A.width/2),R=Math.floor(A.height/2),G=[ze(F,A.width,A.height,_)];return}}}catch{}if(!o.mediaUrl)return;let r=k==="video",a=await Ue(o.mediaUrl,r?In:_e);if(!a||!(r?a.type.startsWith("video/"):a.type.startsWith("image/")))return;let c=U__namespace.join(_t(),"in");try{rt.writeFileSync(c,a.data);}catch{return}let m=Je(c),g=tt("ffmpeg")?Wn(c):null,w=g?.match(/crop=(\d+):(\d+)/),z=w?Number(w[1]):m?.w??16,J=w?Number(w[2]):m?.h??9;if(O&&tt("ffmpeg")&&z>0&&J>0){let C=Math.min(z,J),A=Math.floor((z-C)/2),F=Math.floor((J-C)/2);g=`crop=${C}:${C}:${A}:${F}`,z=C,J=C,w=null;}if(Xe(z,J),!r&&xt==="iterm2"){nt=Le(a.data,{w:N,h:R}),pt=0;return}if(!r&&xt==="kitty"&&a.type==="image/png"){nt=Tn(a.data,{w:N,h:R}),pt=0;return}if(r&&xt==="iterm2"&&tt("ffmpeg"))try{let C=U__namespace.join(_t(),"out.gif");if(child_process.spawnSync("ffmpeg",["-y","-i",c,"-t","6","-vf","fps=8,scale=280:-1:flags=lanczos","-loop","0",C],{timeout:12e3}).status===0){let F=rt.readFileSync(C);if(F.length<=_e){nt=Le(F,{w:N,h:R}),pt=0;return}}}catch{}if(tt("ffmpeg"))try{let C=r||a.type==="image/gif",A=Fn(c,_t(),N,R,C,g)??Un(c,N,R,C,_,g);A&&A.length>0&&(G=A,Pt=0,Qe());}catch{}},Vt=(r=0)=>{if(!st)return;let{kind:a,file:u,vol:c}=st,m=Math.max(0,r/1e3),g,w;a==="afplay"?(g="afplay",w=["-v",c.toFixed(2),u]):a==="ffplay"?(g="ffplay",w=["-nodisp","-autoexit","-volume",String(Math.round(c*100))],m>.2&&w.push("-ss",m.toFixed(2)),w.push(u)):a==="mpv"?(g="mpv",w=["--no-video","--really-quiet",`--volume=${Math.round(c*100)}`],m>.2&&w.push(`--start=${m.toFixed(2)}`),w.push(u)):a==="paplay"?(g="paplay",w=[`--volume=${Math.round(c*65536)}`,u]):(g="mpg123",w=["-q","-f",String(Math.round(32768*c))],m>.2&&w.push("-k",String(Math.round(r/26.12))),w.push(u));try{q=Y?child_process.spawn(g,w,{stdio:"ignore",detached:!0,windowsHide:!0}):child_process.spawn(g,w,{stdio:"ignore"}),H="playing",me=Date.now(),q.on("exit",()=>{H!=="paused"&&(H="ended",Ht=0);});}catch{H="none";}},tn=()=>{try{H==="playing"&&q?(H="paused",Ht+=Date.now()-me,q.kill("SIGKILL"),q=null,de([{type:"sound_muted"}])):H==="paused"?st?.canSeek&&Vt(Ht):H==="ended"&&Vt(0);}catch{}at();},bt=async(r=o.mediaUrl)=>{if(!r||Ye)return;let a=U__namespace.join(Pe.homedir(),".config","opencrater","audio-plays.json");try{let c=[];try{c=JSON.parse(rt.readFileSync(a,"utf8")),Array.isArray(c)||(c=[]);}catch{}let m=Ce(Date.now(),c);if(rt.writeFileSync(a,JSON.stringify(m.next)),!m.play)return}catch{}let u=await Ue(r,On);if(!(!u||!u.type.startsWith("audio/")))try{let c=u.type.includes("wav")?"wav":u.type.includes("ogg")?"ogg":"mp3",m=U__namespace.join(_t(),`ad.${c}`);rt.writeFileSync(m,u.data);let g=Ae(new Date().getHours());if(tt("ffplay"))st={kind:"ffplay",file:m,vol:g,canSeek:!0};else if(!Y&&tt("mpv"))st={kind:"mpv",file:m,vol:g,canSeek:!0};else if(process.platform==="darwin"&&tt("afplay"))st={kind:"afplay",file:m,vol:g,canSeek:!1};else if(!Y&&tt("mpg123")&&c==="mp3")st={kind:"mpg123",file:m,vol:g,canSeek:!0};else if(!Y&&c!=="mp3"&&tt("paplay"))st={kind:"paplay",file:m,vol:g,canSeek:!1};else return;Vt(),setTimeout(()=>{try{q?.kill("SIGKILL");}catch{}(H==="playing"||H==="paused")&&(H="ended");},Ee).unref?.();}catch{}},ve=()=>{if(!o.impressionId||o.replay)return;let r=U__namespace.join(Pe.homedir(),".config","opencrater","dismiss.signal"),a=Date.now();Rt=setInterval(()=>{try{let u=rt.readFileSync(r,"utf8"),c=JSON.parse(u),m=typeof c.at=="number"&&c.at>=a-5e3,g=!c.impressionId||c.impressionId===o.impressionId;if(m&&g){try{rt.unlinkSync(r);}catch{}Lt(o.campaignId),fetch(`${it}/x/${o.impressionId}`,{signal:AbortSignal.timeout(1500)}).catch(()=>{}),K(!0);return}}catch{}(async()=>{try{let u=await fetch(`${it}/v1/events/dismissed/${o.impressionId}`,{signal:AbortSignal.timeout(1200)});if(!u.ok)return;(await u.json()).dismissed&&(Lt(o.campaignId),K(!0));}catch{}})();},vn);},Ie=()=>{if(Ct)return;let r=U__namespace.join(Pe.homedir(),".config","opencrater","activity.signal"),a=Date.now(),u=1500;kt=setInterval(()=>{try{let c=rt.statSync(r).mtimeMs;c>a+u&&c>Date.now()-we&&(ye=c+we,at());}catch{}},150);};if(Y){(async()=>{let r=f.size?await f.size:null;if(r&&r.cols>=24&&(h=r.cols,b=Math.min(D,h-4),v=b-4,j=Math.max(1,h-b-1),T("windows geometry from pump:","cols",h,"width",b,"col",j,"ownerPid",r.pid)),k==="image"||k==="logo"||k==="gif"||k==="video"?await Yt():k==="audio"&&await bt(),o.audioUrl&&k!=="audio"&&bt(o.audioUrl),n){let m=Math.min(Math.max(o.durationMs??se,3e3),12e4);if(ht=Date.now()+m,s)try{rt.unlinkSync(s);}catch{}Fe(f);let g=G,w=!!(g&&g.length>1);at(),ct=setInterval(at,w?Ne:Ut),Ie(),Oe(),ve(),process.on("SIGINT",()=>K(true)),process.on("SIGHUP",()=>K(true)),setTimeout(()=>K(true),m);return}let a=r?.pid??0;a>0&&Nn(o,a)&&(f.close(),process.exit(0)),T("no job-escape (ownerPid",a,") \u2014 bounded toast fallback");let u=Number(process.env.OPENCRATER_WIN_HOLD_MS),c=u>0?u:Math.min(o.durationMs??se,5e3);if(ht=Date.now()+c,f.write(Jt()),await new Promise(m=>{let g=setInterval(()=>{if(Date.now()>=ht){clearInterval(g),m();return}f.write(Jt());},Ut);}),Se(),Q)try{rt.rmSync(Q,{recursive:!0,force:!0});}catch{}await f.closeAndWait(),process.exit(0);})();return}if(Ct){(async()=>{k==="image"||k==="logo"||k==="gif"||k==="video"?await Yt():k==="audio"&&await bt(),o.audioUrl&&k!=="audio"&&bt(o.audioUrl);let r=G;r&&r.length>1&&(G=[r[0]]);let a=ge(),u=" ".repeat(Math.max(0,h-b-2)),c=`\r
|
|
6
|
+
`;for(let g of a)c+=`${u}${g}\r
|
|
7
|
+
`;nt&&R>0&&(c+=`${u}${nt}\r
|
|
8
|
+
`),f.write(c);let m=q?Ee+1e3:250;setTimeout(()=>{if(q)try{q.kill("SIGKILL");}catch{}if(Q)try{rt.rmSync(Q,{recursive:!0,force:!0});}catch{}f.close(),process.exit(0);},m);})();return}at(),ct=setInterval(at,Ut);function Oe(){if(!(!o.impressionId&&!o.replay||Ct))try{let r=crypto.randomBytes(8).toString("hex"),a=je__namespace.createServer((u,c)=>{if(!u.url||!u.url.includes(r)){c.writeHead(404).end();return}if(u.url.startsWith("/p/")){Re(o.campaignId),o.impressionId?(c.writeHead(302,{location:`${it}/r/${o.impressionId}`}),c.end()):(c.writeHead(200,{"content-type":"text/html; charset=utf-8"}),c.end(`<!doctype html><meta charset=utf-8><title>Ad reported</title><body style="font-family:ui-monospace,monospace;background:#0c0c0a;color:#e9e6da;display:grid;place-items:center;height:100vh;margin:0"><p>\u2691 Reported \u2014 you won't see this ad again. This tab closes itself.</p><script>setTimeout(function(){window.close()},600);</script>`)),setTimeout(()=>K(!0),150);return}if(u.url.startsWith("/a/")){tn(),c.writeHead(200,{"content-type":"text/html; charset=utf-8"}),c.end('<!doctype html><meta charset=utf-8><title>Audio</title><body style="font-family:ui-monospace,monospace;background:#0c0c0a;color:#e9e6da;display:grid;place-items:center;height:100vh;margin:0"><p>\u266A toggled \u2014 this tab closes itself.</p><script>setTimeout(function(){window.close()},300);</script>');return}c.writeHead(200,{"content-type":"text/html; charset=utf-8"}),c.end('<!doctype html><meta charset=utf-8><title>Ad dismissed</title><body style="font-family:ui-monospace,monospace;background:#0c0c0a;color:#e9e6da;display:grid;place-items:center;height:100vh;margin:0"><p>\u2715 Ad dismissed \u2014 this tab closes itself.</p><script>setTimeout(function(){window.close()},400);</script>'),Lt(o.campaignId),!o.replay&&o.impressionId&&fetch(`${it}/x/${o.impressionId}`,{signal:AbortSignal.timeout(2e3)}).catch(()=>{}),setTimeout(()=>K(!0),150);});a.unref(),a.listen(0,"127.0.0.1",()=>{let u=a.address();u&&typeof u=="object"&&(gt=`http://127.0.0.1:${u.port}/x/${r}`,Bt=`http://127.0.0.1:${u.port}/a/${r}`,Gt=`http://127.0.0.1:${u.port}/p/${r}`,Nt=a,at());}),a.on("error",()=>{gt=null,Gt=null;});}catch{}}try{rt.writeFileSync(U__namespace.join(Pe.homedir(),".config","opencrater","last-ad.json"),JSON.stringify({payload:o,at:Date.now()}));}catch{}Oe(),ve(),Ie(),k==="image"||k==="logo"||k==="gif"||k==="video"?Yt():k==="audio"&&bt(),o.audioUrl&&k!=="audio"&&bt(o.audioUrl);let Xt=o.durationMs??(k==="video"?18e3:k==="audio"?16e3:se);ht=Date.now()+Xt,setTimeout(()=>K(true),Xt),process.on("SIGTERM",()=>K(true)),process.on("SIGINT",()=>K(true)),process.on("SIGHUP",()=>K(true)),setTimeout(()=>K(true),Xt+5e3).unref?.();}typeof ee<"u"&&typeof module<"u"&&ee.main===module&&Hn();
|
|
9
|
+
exports.windowsVtOk=cr;
|