agent-yes 1.238.2 → 1.239.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/dist/{SUPPORTED_CLIS-C2CFOND-.js → SUPPORTED_CLIS-B1KpRTn6.js} +2 -2
- package/dist/{SUPPORTED_CLIS-DmflHNKL.js → SUPPORTED_CLIS-BAjpiDmM.js} +3 -3
- package/dist/{agentShare-CyDqjBM_.js → agentShare-6AJaJhF_.js} +5 -5
- package/dist/{browser-BRMyG4JA.js → browser-CEP6GcDq.js} +2 -2
- package/dist/{callback-D-kUTlR6.js → callback-DWCY5gUu.js} +5 -5
- package/dist/{callback-Bb5dBd02.js → callback-FXxZhg1N.js} +5 -5
- package/dist/{callbackCore-CvmGSvrj.js → callbackCore-Cd4mYekY.js} +1 -1
- package/dist/{callbackCore-DAYcemCC.js → callbackCore-Dd28_cBM.js} +1 -1
- package/dist/{channels-CMNMFJlY.js → channels-H4PBBker.js} +2 -2
- package/dist/chunk-CNLfOXRf.js +43 -0
- package/dist/cli.js +11 -11
- package/dist/{cwdConflictWarn-DWHWlBxS.js → cwdConflictWarn-DEJHqTZ4.js} +1 -1
- package/dist/{cwdDeprecation-Cd8Ykm2t.js → cwdDeprecation-Cd-4t7lI.js} +1 -1
- package/dist/{expose-DROTwbyU.js → expose-Ct28jckQ.js} +1 -1
- package/dist/{forkNested-DqPisz9d.js → forkNested-BW2OmXjA.js} +1 -1
- package/dist/html2canvas-CWk6nh1H.js +6718 -0
- package/dist/index.js +2 -2
- package/dist/{nodeRuntime-Bf88NPqj.js → nodeRuntime-BtL6Oo1o.js} +1 -1
- package/dist/{notifyDaemon-BjyUCpbx.js → notifyDaemon-DrLqT7fy.js} +4 -4
- package/dist/{openBrowser-ChLcPELv.js → openBrowser-DifNZwyn.js} +1 -1
- package/dist/{remotes-Bem6WIyU.js → remotes-BxQnNxQv.js} +3 -3
- package/dist/{remotes-BClMgQZW.js → remotes-DNLZlk9U.js} +2 -2
- package/dist/{rustBinary-CCi6Sqh5.js → rustBinary-BDoH3nyt.js} +2 -2
- package/dist/{schedule-CHSe24Je.js → schedule-Br--S5qc.js} +6 -6
- package/dist/{serve-CuMtnSLs.js → serve-DyQ-oFbD.js} +28 -27
- package/dist/{setup-wPtsNZZ5.js → setup-BEwSgz1-.js} +3 -3
- package/dist/{share-B9u8-I3y.js → share-BGl3wutJ.js} +1 -1
- package/dist/{share--aHaPSjt.js → share-DchOdgBz.js} +1 -1
- package/dist/{spawnGate-Bo_LFgt9.js → spawnGate-BxgS_GlF.js} +2 -2
- package/dist/{spawnGate-CuWCd2im.js → spawnGate-Dc3odVqo.js} +1 -1
- package/dist/{subcommands-z2YriUNK.js → subcommands-CCsfQjn6.js} +3 -3
- package/dist/{subcommands-CuvZqZTM.js → subcommands-CImOH-GZ.js} +18 -18
- package/dist/{terminal-CBbBQMcT.js → terminal-oxQ_KbyG.js} +2 -2
- package/dist/terminal.js +1 -1
- package/dist/{todoCli-CNNR9Czu.js → todoCli-DhD3G8Et.js} +1 -1
- package/dist/{tray-D5qFaqlS.js → tray-DpswPpBI.js} +1 -1
- package/dist/{ts-Cnhsw8GN.js → ts-Dg43iOPE.js} +3 -3
- package/dist/{versionChecker-CBzYImFt.js → versionChecker-D8DinCka.js} +2 -2
- package/dist/{webrtcLink-VQhWmKOw.js → webrtcLink-BMYneHbu.js} +1 -1
- package/dist/{webrtcRemote-DJDtCTpj.js → webrtcRemote-D9ENKmzx.js} +2 -2
- package/dist/{widget-j4TWqwpU.js → widget-CBPw56Wj.js} +29 -5
- package/dist/widget.js +124 -0
- package/dist/widgets.js +1 -1
- package/dist/{workspaceConfig-B7HaQ-MI.js → workspaceConfig-DOHygA2x.js} +1 -1
- package/dist/{ws-53rrEEbz.js → ws-RYCFiAx-.js} +5 -5
- package/package.json +4 -3
- package/ts/serve.ts +3 -1
- package/ts/widget.ts +36 -2
- package/dist/chunk-cZBX9HZv.js +0 -20
|
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
|
|
|
28
28
|
}
|
|
29
29
|
/** Resolve the local daemon base URL + token (flags override discovery). */
|
|
30
30
|
async function daemonTarget(flags) {
|
|
31
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
31
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DyQ-oFbD.js");
|
|
32
32
|
const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
|
|
33
33
|
if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
|
|
34
34
|
const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
|
|
@@ -69,18 +69,25 @@ async function cmdWidgetRead(args) {
|
|
|
69
69
|
text: "bool",
|
|
70
70
|
html: "bool",
|
|
71
71
|
json: "bool",
|
|
72
|
+
viewport: "bool",
|
|
73
|
+
selection: "bool",
|
|
74
|
+
out: "value",
|
|
72
75
|
base: "value",
|
|
73
76
|
token: "value"
|
|
74
77
|
});
|
|
75
78
|
const kind = positional[0];
|
|
76
79
|
const viewer = positional[1];
|
|
77
|
-
if (!kind || !viewer) throw new Error("usage: ay widget read <selection|dom> <viewer> [--selector <css>] [--all] [--text|--html]");
|
|
80
|
+
if (!kind || !viewer) throw new Error("usage: ay widget read <selection|dom|screenshot> <viewer> [--selector <css>] [--all] [--text|--html] [--viewport|--selection] [--out f.png] [--json]");
|
|
78
81
|
const cmdArgs = {};
|
|
79
82
|
if (kind === "dom") {
|
|
80
83
|
if (typeof flags.selector !== "string") throw new Error("dom read needs --selector <css>");
|
|
81
84
|
cmdArgs.selector = flags.selector;
|
|
82
85
|
cmdArgs.all = flags.all === true;
|
|
83
86
|
}
|
|
87
|
+
if (kind === "screenshot") {
|
|
88
|
+
cmdArgs.mode = typeof flags.selector === "string" ? "selector" : flags.selection ? "selection" : "viewport";
|
|
89
|
+
if (cmdArgs.mode === "selector") cmdArgs.selector = flags.selector;
|
|
90
|
+
}
|
|
84
91
|
const { base, token } = await daemonTarget(flags);
|
|
85
92
|
const res = await fetch(withTok(`${base}/api/widget/read`, token), {
|
|
86
93
|
method: "POST",
|
|
@@ -97,6 +104,23 @@ async function cmdWidgetRead(args) {
|
|
|
97
104
|
process.stderr.write(`read ${kind} @ ${body.viewer ?? viewer}: ${body.error}\n`);
|
|
98
105
|
return 1;
|
|
99
106
|
}
|
|
107
|
+
if (kind === "screenshot") {
|
|
108
|
+
const d = body.data ?? {};
|
|
109
|
+
if (typeof flags.out === "string") {
|
|
110
|
+
const { writeFile } = await import("fs/promises");
|
|
111
|
+
const buf = Buffer.from(String(d.b64 ?? ""), "base64");
|
|
112
|
+
await writeFile(flags.out, buf);
|
|
113
|
+
process.stderr.write(`wrote ${buf.length} bytes → ${flags.out} (${d.w}×${d.h} ${d.mime})\n`);
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
if (flags.json) {
|
|
117
|
+
process.stdout.write(JSON.stringify(body, null, 2) + "\n");
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
const bytes = Math.round(String(d.b64 ?? "").length * 3 / 4);
|
|
121
|
+
process.stdout.write(`screenshot ${d.w}×${d.h} ${d.mime}, ~${bytes} bytes — use --out <f.png> to save or --json for the base64\n`);
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
100
124
|
if (kind === "selection" && !flags.json) {
|
|
101
125
|
process.stdout.write((flags.html ? body.data?.html : body.data?.text) ?? "");
|
|
102
126
|
process.stdout.write("\n");
|
|
@@ -106,7 +130,7 @@ async function cmdWidgetRead(args) {
|
|
|
106
130
|
return 0;
|
|
107
131
|
}
|
|
108
132
|
function widgetHelp() {
|
|
109
|
-
process.stdout.write("ay widget — read an opted-in page widget's context (selection / DOM)\n\nUsage:\n ay widget ls [--json]\n ay widget read selection <viewer> [--text|--html|--json]\n ay widget read dom <viewer> --selector <css> [--all] [--json]\n\n <viewer> = an id, or a url/title substring (see `ay widget ls`).\n Common flags: --base <daemon-url> --token <tok> (default: the local daemon).\n The page must embed `new AyWidget({sensors:[...]}).start()` and the token must\n carry the 'read' cap (ay mint <viewer> --caps read) — or use the master token.\n");
|
|
133
|
+
process.stdout.write("ay widget — read an opted-in page widget's context (selection / DOM)\n\nUsage:\n ay widget ls [--json]\n ay widget read selection <viewer> [--text|--html|--json]\n ay widget read dom <viewer> --selector <css> [--all] [--json]\n ay widget read screenshot <viewer> [--viewport|--selector <css>|--selection] [--out f.png] [--json]\n\n <viewer> = an id, or a url/title substring (see `ay widget ls`).\n Common flags: --base <daemon-url> --token <tok> (default: the local daemon).\n The page must embed `new AyWidget({sensors:[...]}).start()` and the token must\n carry the 'read' cap (ay mint <viewer> --caps read) — or use the master token.\n");
|
|
110
134
|
return 0;
|
|
111
135
|
}
|
|
112
136
|
async function cmdWidget(args) {
|
|
@@ -153,7 +177,7 @@ async function cmdMint(args) {
|
|
|
153
177
|
const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
|
|
154
178
|
if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
|
|
155
179
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
156
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
180
|
+
const { mintScopedTermToken } = await import("./serve-DyQ-oFbD.js");
|
|
157
181
|
const r = await mintScopedTermToken(target, {
|
|
158
182
|
ttlSec,
|
|
159
183
|
caps
|
|
@@ -169,4 +193,4 @@ async function cmdMint(args) {
|
|
|
169
193
|
|
|
170
194
|
//#endregion
|
|
171
195
|
export { cmdMint, cmdWidget };
|
|
172
|
-
//# sourceMappingURL=widget-
|
|
196
|
+
//# sourceMappingURL=widget-CBPw56Wj.js.map
|
package/dist/widget.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { i as __toESM } from "./chunk-CNLfOXRf.js";
|
|
2
|
+
|
|
1
3
|
//#region ts/widget/browser.ts
|
|
2
4
|
var AyWidget = class {
|
|
3
5
|
origin;
|
|
@@ -22,6 +24,7 @@ var AyWidget = class {
|
|
|
22
24
|
}));
|
|
23
25
|
this.handlers.set("selection", readSelection);
|
|
24
26
|
this.handlers.set("dom", readDom);
|
|
27
|
+
this.handlers.set("screenshot", (a) => this.readScreenshot(a));
|
|
25
28
|
}
|
|
26
29
|
url(path) {
|
|
27
30
|
const p = this.token ? `${path}${path.includes("?") ? "&" : "?"}token=${encodeURIComponent(this.token)}` : path;
|
|
@@ -111,6 +114,99 @@ var AyWidget = class {
|
|
|
111
114
|
clearTimeout(el._t);
|
|
112
115
|
el._t = setTimeout(() => el.style.opacity = "0", 500);
|
|
113
116
|
}
|
|
117
|
+
async readScreenshot(args) {
|
|
118
|
+
const g = globalThis;
|
|
119
|
+
const doc = g.document;
|
|
120
|
+
if (!await this.ensureScreenshotConsent()) throw new Error("screenshot declined by viewer");
|
|
121
|
+
const mode = args?.mode ?? "viewport";
|
|
122
|
+
if (mode === "selector") {
|
|
123
|
+
if (!args?.selector) throw new Error("screenshot --selector needs a css selector");
|
|
124
|
+
const el = doc.querySelector(args.selector);
|
|
125
|
+
if (!el) throw new Error(`no element matches ${args.selector}`);
|
|
126
|
+
const hook = this.snapshotFor(el);
|
|
127
|
+
if (hook) return dataUrlResult(hook, el.width, el.height);
|
|
128
|
+
return canvasResult(await this.h2c(el, false));
|
|
129
|
+
}
|
|
130
|
+
if (mode === "selection") {
|
|
131
|
+
const sel = g.getSelection?.();
|
|
132
|
+
const rect = sel && sel.rangeCount ? sel.getRangeAt(0).getBoundingClientRect() : null;
|
|
133
|
+
return canvasResult(await this.h2c(g.document.body, true, rect));
|
|
134
|
+
}
|
|
135
|
+
return canvasResult(await this.h2c(g.document.body, true, null));
|
|
136
|
+
}
|
|
137
|
+
/** A registered snapshot hook whose element IS `el` (identity / matches) → its dataURL, else null. */
|
|
138
|
+
snapshotFor(el) {
|
|
139
|
+
const doc = globalThis.document;
|
|
140
|
+
for (const key of Object.keys(this.snapshots)) try {
|
|
141
|
+
if (el === doc.querySelector(key) || el.matches?.(key)) return this.snapshots[key]();
|
|
142
|
+
} catch {}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
async h2c(el, viewport, rect) {
|
|
146
|
+
const g = globalThis;
|
|
147
|
+
const mod = await import("./html2canvas-CWk6nh1H.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
|
|
148
|
+
const html2canvas = mod.default ?? mod;
|
|
149
|
+
const opts = {
|
|
150
|
+
backgroundColor: viewport ? "#ffffff" : null,
|
|
151
|
+
logging: false,
|
|
152
|
+
useCORS: true,
|
|
153
|
+
scale: g.devicePixelRatio || 1,
|
|
154
|
+
onclone: (d) => this.swapSnapshots(d)
|
|
155
|
+
};
|
|
156
|
+
if (rect) {
|
|
157
|
+
opts.x = rect.left + (g.scrollX || 0);
|
|
158
|
+
opts.y = rect.top + (g.scrollY || 0);
|
|
159
|
+
opts.width = Math.max(1, rect.width);
|
|
160
|
+
opts.height = Math.max(1, rect.height);
|
|
161
|
+
}
|
|
162
|
+
return html2canvas(el, opts);
|
|
163
|
+
}
|
|
164
|
+
/** In the doc html2canvas clones, replace each registered WebGL canvas with the hook's <img>. */
|
|
165
|
+
swapSnapshots(clonedDoc) {
|
|
166
|
+
const liveDoc = globalThis.document;
|
|
167
|
+
for (const key of Object.keys(this.snapshots)) try {
|
|
168
|
+
const liveEl = liveDoc.querySelector(key);
|
|
169
|
+
const cloneEl = clonedDoc.querySelector(key);
|
|
170
|
+
if (!liveEl || !cloneEl?.parentNode) continue;
|
|
171
|
+
const img = clonedDoc.createElement("img");
|
|
172
|
+
img.src = this.snapshots[key]();
|
|
173
|
+
const r = liveEl.getBoundingClientRect();
|
|
174
|
+
img.width = Math.round(r.width);
|
|
175
|
+
img.height = Math.round(r.height);
|
|
176
|
+
img.style.cssText = cloneEl.getAttribute?.("style") ?? "";
|
|
177
|
+
cloneEl.parentNode.replaceChild(img, cloneEl);
|
|
178
|
+
} catch {}
|
|
179
|
+
}
|
|
180
|
+
/** One-time per-viewer screenshot consent (remembered), auto-denying before the daemon read times out. */
|
|
181
|
+
async ensureScreenshotConsent() {
|
|
182
|
+
const g = globalThis;
|
|
183
|
+
const doc = g.document;
|
|
184
|
+
const key = `ay29widget:screenshot-ok:${this.viewerId}`;
|
|
185
|
+
try {
|
|
186
|
+
if (g.localStorage?.getItem(key) === "1") return true;
|
|
187
|
+
} catch {}
|
|
188
|
+
if (!doc?.body) return false;
|
|
189
|
+
return await new Promise((resolve) => {
|
|
190
|
+
const host = doc.createElement("div");
|
|
191
|
+
const root = host.attachShadow({ mode: "open" });
|
|
192
|
+
root.innerHTML = CONSENT_HTML;
|
|
193
|
+
doc.body.appendChild(host);
|
|
194
|
+
let settled = false;
|
|
195
|
+
const timer = setTimeout(() => done(false), 25e3);
|
|
196
|
+
function done(ok) {
|
|
197
|
+
if (settled) return;
|
|
198
|
+
settled = true;
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
host.remove();
|
|
201
|
+
if (ok) try {
|
|
202
|
+
g.localStorage?.setItem(key, "1");
|
|
203
|
+
} catch {}
|
|
204
|
+
resolve(ok);
|
|
205
|
+
}
|
|
206
|
+
root.getElementById("ay-ss-ok")?.addEventListener("click", () => done(true));
|
|
207
|
+
root.getElementById("ay-ss-no")?.addEventListener("click", () => done(false));
|
|
208
|
+
});
|
|
209
|
+
}
|
|
114
210
|
stop() {
|
|
115
211
|
this.es?.close?.();
|
|
116
212
|
this.es = void 0;
|
|
@@ -119,6 +215,34 @@ var AyWidget = class {
|
|
|
119
215
|
this.started = false;
|
|
120
216
|
}
|
|
121
217
|
};
|
|
218
|
+
function dataUrlResult(url, w = 0, h = 0) {
|
|
219
|
+
const b64 = String(url).replace(/^data:[^,]*,/, "");
|
|
220
|
+
return {
|
|
221
|
+
mime: "image/png",
|
|
222
|
+
w: Number(w) || 0,
|
|
223
|
+
h: Number(h) || 0,
|
|
224
|
+
b64
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function canvasResult(canvas) {
|
|
228
|
+
return dataUrlResult(canvas.toDataURL("image/png"), canvas.width, canvas.height);
|
|
229
|
+
}
|
|
230
|
+
const CONSENT_HTML = `
|
|
231
|
+
<style>
|
|
232
|
+
:host { all: initial; }
|
|
233
|
+
.bar { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 2147483001;
|
|
234
|
+
display: flex; align-items: center; gap: 10px; background: #161b22; color: #c9d1d9;
|
|
235
|
+
border: 1px solid #30363d; border-radius: 10px; padding: 10px 14px;
|
|
236
|
+
font: 13px system-ui, -apple-system, sans-serif; box-shadow: 0 8px 30px rgba(0,0,0,.4); }
|
|
237
|
+
button { border: none; border-radius: 7px; padding: 6px 12px; cursor: pointer; font: inherit; }
|
|
238
|
+
#ay-ss-ok { background: #1f6feb; color: #fff; }
|
|
239
|
+
#ay-ss-no { background: #30363d; color: #c9d1d9; }
|
|
240
|
+
</style>
|
|
241
|
+
<div class="bar">
|
|
242
|
+
<span>This page's agent wants to capture the current view.</span>
|
|
243
|
+
<button id="ay-ss-ok">Allow</button>
|
|
244
|
+
<button id="ay-ss-no">Deny</button>
|
|
245
|
+
</div>`;
|
|
122
246
|
async function readSelection() {
|
|
123
247
|
const g = globalThis;
|
|
124
248
|
const sel = g.getSelection?.();
|
package/dist/widgets.js
CHANGED
|
@@ -2,7 +2,7 @@ import "./e2e-CEIdJGZ7.js";
|
|
|
2
2
|
import "./channels-BiGUYTuz.js";
|
|
3
3
|
import "./peer-B5JKF4BP.js";
|
|
4
4
|
import { t as AyChannel } from "./browser-B3dOptjL.js";
|
|
5
|
-
import { t as AyTerminal } from "./browser-
|
|
5
|
+
import { t as AyTerminal } from "./browser-CEP6GcDq.js";
|
|
6
6
|
import { AyWidget } from "./widget.js";
|
|
7
7
|
|
|
8
8
|
export { AyChannel, AyTerminal, AyWidget };
|
|
@@ -193,4 +193,4 @@ function resolveSpawnCwd(input) {
|
|
|
193
193
|
|
|
194
194
|
//#endregion
|
|
195
195
|
export { getSpawnHook as a, hasProvisionHook as c, resolveSpawnCwd as d, setWorkspaceRoot as f, getProvisionRoot as i, hasSpawnHook as l, getMinFreeMb as n, getSpawnWaitMs as o, getProvisionHook as r, getWorkspaceRoot as s, getMaxAgents as t, isProvisionAllowed as u };
|
|
196
|
-
//# sourceMappingURL=workspaceConfig-
|
|
196
|
+
//# sourceMappingURL=workspaceConfig-DOHygA2x.js.map
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.js";
|
|
6
|
-
import { C as listRecords } from "./subcommands-
|
|
7
|
-
import "./webrtcLink-
|
|
8
|
-
import "./remotes-
|
|
9
|
-
import { i as getProvisionRoot } from "./workspaceConfig-
|
|
6
|
+
import { C as listRecords } from "./subcommands-CImOH-GZ.js";
|
|
7
|
+
import "./webrtcLink-BMYneHbu.js";
|
|
8
|
+
import "./remotes-BxQnNxQv.js";
|
|
9
|
+
import { i as getProvisionRoot } from "./workspaceConfig-DOHygA2x.js";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
11
|
import { lstat, opendir } from "fs/promises";
|
|
12
12
|
import path from "path";
|
|
@@ -418,4 +418,4 @@ async function cmdWs(args) {
|
|
|
418
418
|
|
|
419
419
|
//#endregion
|
|
420
420
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
|
|
421
|
-
//# sourceMappingURL=ws-
|
|
421
|
+
//# sourceMappingURL=ws-RYCFiAx-.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.239.0",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -148,8 +148,6 @@
|
|
|
148
148
|
},
|
|
149
149
|
"devDependencies": {
|
|
150
150
|
"@google/generative-ai": "^0.24.1",
|
|
151
|
-
"@xterm/addon-fit": "^0.11.0",
|
|
152
|
-
"@xterm/xterm": "^6.0.0",
|
|
153
151
|
"@semantic-release/exec": "^7.1.0",
|
|
154
152
|
"@semantic-release/git": "^10.0.1",
|
|
155
153
|
"@types/bun": "^1.3.6",
|
|
@@ -161,7 +159,10 @@
|
|
|
161
159
|
"@types/yargs": "^17.0.35",
|
|
162
160
|
"@typescript/native-preview": "^7.0.0-dev.20260124.1",
|
|
163
161
|
"@vitest/coverage-v8": "4.1.0",
|
|
162
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
163
|
+
"@xterm/xterm": "^6.0.0",
|
|
164
164
|
"codehost": "^0.32.0",
|
|
165
|
+
"html2canvas": "^1.4.1",
|
|
165
166
|
"husky": "^9.1.7",
|
|
166
167
|
"lint-staged": "^16.2.7",
|
|
167
168
|
"node-pty": "^1.1.0",
|
package/ts/serve.ts
CHANGED
|
@@ -3083,11 +3083,13 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
3083
3083
|
const push = widgetPushers.get(vid);
|
|
3084
3084
|
if (!push) return new Response("viewer offline", { status: 409 });
|
|
3085
3085
|
const cmdId = `c${++widgetCmdSeq}_${Date.now()}`;
|
|
3086
|
+
// Screenshot waits on a human one-time consent, so it gets a longer window.
|
|
3087
|
+
const readTimeoutMs = b.kind === "screenshot" ? 30_000 : 10_000;
|
|
3086
3088
|
const result = await new Promise<{ ok: boolean; data?: unknown; error?: string }>((resolve) => {
|
|
3087
3089
|
const timer = setTimeout(() => {
|
|
3088
3090
|
widgetWaiters.delete(cmdId);
|
|
3089
3091
|
resolve({ ok: false, error: "timeout" });
|
|
3090
|
-
},
|
|
3092
|
+
}, readTimeoutMs);
|
|
3091
3093
|
widgetWaiters.set(cmdId, (r) => {
|
|
3092
3094
|
clearTimeout(timer);
|
|
3093
3095
|
resolve(r);
|
package/ts/widget.ts
CHANGED
|
@@ -95,19 +95,31 @@ async function cmdWidgetRead(args: string[]): Promise<number> {
|
|
|
95
95
|
text: "bool",
|
|
96
96
|
html: "bool",
|
|
97
97
|
json: "bool",
|
|
98
|
+
viewport: "bool",
|
|
99
|
+
selection: "bool",
|
|
100
|
+
out: "value",
|
|
98
101
|
base: "value",
|
|
99
102
|
token: "value",
|
|
100
103
|
});
|
|
101
104
|
const kind = positional[0];
|
|
102
105
|
const viewer = positional[1];
|
|
103
106
|
if (!kind || !viewer)
|
|
104
|
-
throw new Error(
|
|
107
|
+
throw new Error(
|
|
108
|
+
"usage: ay widget read <selection|dom|screenshot> <viewer> [--selector <css>] [--all] [--text|--html] " +
|
|
109
|
+
"[--viewport|--selection] [--out f.png] [--json]",
|
|
110
|
+
);
|
|
105
111
|
const cmdArgs: Record<string, unknown> = {};
|
|
106
112
|
if (kind === "dom") {
|
|
107
113
|
if (typeof flags.selector !== "string") throw new Error("dom read needs --selector <css>");
|
|
108
114
|
cmdArgs.selector = flags.selector;
|
|
109
115
|
cmdArgs.all = flags.all === true;
|
|
110
116
|
}
|
|
117
|
+
if (kind === "screenshot") {
|
|
118
|
+
// exactly one region mode; --selector implies selector mode, else --selection, else --viewport
|
|
119
|
+
cmdArgs.mode =
|
|
120
|
+
typeof flags.selector === "string" ? "selector" : flags.selection ? "selection" : "viewport";
|
|
121
|
+
if (cmdArgs.mode === "selector") cmdArgs.selector = flags.selector;
|
|
122
|
+
}
|
|
111
123
|
const { base, token } = await daemonTarget(flags);
|
|
112
124
|
const res = await fetch(withTok(`${base}/api/widget/read`, token), {
|
|
113
125
|
method: "POST",
|
|
@@ -120,6 +132,27 @@ async function cmdWidgetRead(args: string[]): Promise<number> {
|
|
|
120
132
|
process.stderr.write(`read ${kind} @ ${body.viewer ?? viewer}: ${body.error}\n`);
|
|
121
133
|
return 1;
|
|
122
134
|
}
|
|
135
|
+
// Screenshot: --out writes the PNG; else --json gives the envelope; else a summary
|
|
136
|
+
// (the base64 is large, so we don't dump it by default).
|
|
137
|
+
if (kind === "screenshot") {
|
|
138
|
+
const d = body.data ?? {};
|
|
139
|
+
if (typeof flags.out === "string") {
|
|
140
|
+
const { writeFile } = await import("fs/promises");
|
|
141
|
+
const buf = Buffer.from(String(d.b64 ?? ""), "base64");
|
|
142
|
+
await writeFile(flags.out, buf);
|
|
143
|
+
process.stderr.write(`wrote ${buf.length} bytes → ${flags.out} (${d.w}×${d.h} ${d.mime})\n`);
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
if (flags.json) {
|
|
147
|
+
process.stdout.write(JSON.stringify(body, null, 2) + "\n");
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
const bytes = Math.round((String(d.b64 ?? "").length * 3) / 4);
|
|
151
|
+
process.stdout.write(
|
|
152
|
+
`screenshot ${d.w}×${d.h} ${d.mime}, ~${bytes} bytes — use --out <f.png> to save or --json for the base64\n`,
|
|
153
|
+
);
|
|
154
|
+
return 0;
|
|
155
|
+
}
|
|
123
156
|
// Plain-text shortcut for selection unless --json/--html asked for the envelope.
|
|
124
157
|
if (kind === "selection" && !flags.json) {
|
|
125
158
|
process.stdout.write((flags.html ? body.data?.html : body.data?.text) ?? "");
|
|
@@ -136,7 +169,8 @@ function widgetHelp(): number {
|
|
|
136
169
|
`Usage:\n` +
|
|
137
170
|
` ay widget ls [--json]\n` +
|
|
138
171
|
` ay widget read selection <viewer> [--text|--html|--json]\n` +
|
|
139
|
-
` ay widget read dom <viewer> --selector <css> [--all] [--json]\n
|
|
172
|
+
` ay widget read dom <viewer> --selector <css> [--all] [--json]\n` +
|
|
173
|
+
` ay widget read screenshot <viewer> [--viewport|--selector <css>|--selection] [--out f.png] [--json]\n\n` +
|
|
140
174
|
` <viewer> = an id, or a url/title substring (see \`ay widget ls\`).\n` +
|
|
141
175
|
` Common flags: --base <daemon-url> --token <tok> (default: the local daemon).\n` +
|
|
142
176
|
` The page must embed \`new AyWidget({sensors:[...]}).start()\` and the token must\n` +
|
package/dist/chunk-cZBX9HZv.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
4
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
5
|
-
var __exportAll = (all, no_symbols) => {
|
|
6
|
-
let target = {};
|
|
7
|
-
for (var name in all) {
|
|
8
|
-
__defProp(target, name, {
|
|
9
|
-
get: all[name],
|
|
10
|
-
enumerable: true
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
if (!no_symbols) {
|
|
14
|
-
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
15
|
-
}
|
|
16
|
-
return target;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
//#endregion
|
|
20
|
-
export { __esmMin as n, __exportAll as r, __commonJSMin as t };
|