replicas-cli 0.2.424 → 0.2.425
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/index.mjs +95 -43
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -24492,7 +24492,7 @@ function formatTurnElapsed(ms) {
|
|
|
24492
24492
|
}
|
|
24493
24493
|
|
|
24494
24494
|
// ../shared/src/cli-version.ts
|
|
24495
|
-
var CLI_VERSION = "0.2.
|
|
24495
|
+
var CLI_VERSION = "0.2.425";
|
|
24496
24496
|
|
|
24497
24497
|
// ../shared/src/version.ts
|
|
24498
24498
|
function compareVersions(v1, v2) {
|
|
@@ -30365,6 +30365,42 @@ async function serviceLogsCommand(name, options) {
|
|
|
30365
30365
|
}
|
|
30366
30366
|
|
|
30367
30367
|
// src/commands/learnings.ts
|
|
30368
|
+
import { createHash as createHash2 } from "crypto";
|
|
30369
|
+
import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
30370
|
+
import { join as join2 } from "path";
|
|
30371
|
+
var SESSIONS_DIR = join2(CONFIG_DIR, "learnings-sessions");
|
|
30372
|
+
var REPRINT_AFTER_READS = 50;
|
|
30373
|
+
var SESSION_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
30374
|
+
function sessionFilePath() {
|
|
30375
|
+
const key = process.env.REPLICAS_CHAT_ID || process.env.CLAUDE_CODE_SESSION_ID;
|
|
30376
|
+
return key ? join2(SESSIONS_DIR, `${key.replace(/[^a-zA-Z0-9_-]/g, "-")}.json`) : null;
|
|
30377
|
+
}
|
|
30378
|
+
function readSession(path6) {
|
|
30379
|
+
const session = { reads: 0, shown: {} };
|
|
30380
|
+
try {
|
|
30381
|
+
const parsed = JSON.parse(readFileSync2(path6, "utf-8"));
|
|
30382
|
+
if (typeof parsed?.reads === "number") session.reads = parsed.reads;
|
|
30383
|
+
const shown = parsed?.shown ?? {};
|
|
30384
|
+
for (const [id, entry] of Object.entries(shown)) {
|
|
30385
|
+
if (typeof entry?.read === "number" && typeof entry?.hash === "string") {
|
|
30386
|
+
session.shown[id] = { read: entry.read, hash: entry.hash };
|
|
30387
|
+
}
|
|
30388
|
+
}
|
|
30389
|
+
} catch {
|
|
30390
|
+
}
|
|
30391
|
+
return session;
|
|
30392
|
+
}
|
|
30393
|
+
function writeSession(path6, session) {
|
|
30394
|
+
try {
|
|
30395
|
+
mkdirSync2(SESSIONS_DIR, { recursive: true, mode: 448 });
|
|
30396
|
+
writeFileSync2(path6, JSON.stringify(session), { mode: 384 });
|
|
30397
|
+
for (const entry of readdirSync2(SESSIONS_DIR)) {
|
|
30398
|
+
const file2 = join2(SESSIONS_DIR, entry);
|
|
30399
|
+
if (Date.now() - statSync(file2).mtimeMs > SESSION_TTL_MS) unlinkSync(file2);
|
|
30400
|
+
}
|
|
30401
|
+
} catch {
|
|
30402
|
+
}
|
|
30403
|
+
}
|
|
30368
30404
|
function printBlocks(learnings) {
|
|
30369
30405
|
for (const learning of learnings) {
|
|
30370
30406
|
const labels = [
|
|
@@ -30385,14 +30421,30 @@ async function learningsReadCommand(options) {
|
|
|
30385
30421
|
method: "POST",
|
|
30386
30422
|
body: { query }
|
|
30387
30423
|
});
|
|
30424
|
+
const path6 = sessionFilePath();
|
|
30425
|
+
const session = path6 ? readSession(path6) : null;
|
|
30426
|
+
if (session) session.reads += 1;
|
|
30427
|
+
const unseen = response.learnings.filter((learning) => {
|
|
30428
|
+
if (!session) return true;
|
|
30429
|
+
const hash2 = createHash2("sha256").update(learning.content).digest("hex").slice(0, 16);
|
|
30430
|
+
const shown = session.shown[learning.id];
|
|
30431
|
+
if (!options.fresh && shown && shown.hash === hash2 && session.reads - shown.read < REPRINT_AFTER_READS) {
|
|
30432
|
+
return false;
|
|
30433
|
+
}
|
|
30434
|
+
session.shown[learning.id] = { read: session.reads, hash: hash2 };
|
|
30435
|
+
return true;
|
|
30436
|
+
});
|
|
30388
30437
|
if (response.learnings.length === 0) {
|
|
30389
30438
|
console.log("No learnings matched this query.");
|
|
30439
|
+
} else if (unseen.length === 0) {
|
|
30440
|
+
console.log("No new learnings \u2014 the matching ones were already shown earlier in this session.");
|
|
30390
30441
|
} else {
|
|
30391
|
-
printBlocks(
|
|
30442
|
+
printBlocks(unseen);
|
|
30392
30443
|
}
|
|
30393
30444
|
if (response.matching_degraded) {
|
|
30394
30445
|
console.log("Note: trigger matching was unavailable \u2014 only always-apply learnings are shown.");
|
|
30395
30446
|
}
|
|
30447
|
+
if (path6 && session) writeSession(path6, session);
|
|
30396
30448
|
}
|
|
30397
30449
|
async function propose(request) {
|
|
30398
30450
|
const { proposal } = await agentFetch("/v1/agent/learnings/proposals", {
|
|
@@ -30442,14 +30494,14 @@ async function learningsWithdrawCommand(id) {
|
|
|
30442
30494
|
|
|
30443
30495
|
// src/commands/computer/index.ts
|
|
30444
30496
|
import { spawn as spawn5, spawnSync as spawnSync3 } from "child_process";
|
|
30445
|
-
import { createHash as
|
|
30446
|
-
import { closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as
|
|
30497
|
+
import { createHash as createHash3 } from "crypto";
|
|
30498
|
+
import { closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync5, readSync, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
30447
30499
|
import { dirname as dirname3 } from "path";
|
|
30448
30500
|
import chalk21 from "chalk";
|
|
30449
30501
|
|
|
30450
30502
|
// src/commands/computer/desktop.ts
|
|
30451
30503
|
import { spawnSync } from "child_process";
|
|
30452
|
-
import { existsSync, mkdirSync as
|
|
30504
|
+
import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "fs";
|
|
30453
30505
|
import { dirname, isAbsolute, resolve as resolve2 } from "path";
|
|
30454
30506
|
var STATE_DIR = process.env.REPLICAS_DESKTOP_STATE_DIR || "/tmp/replicas-computer";
|
|
30455
30507
|
var DEFAULT_DISPLAY = process.env.REPLICAS_DESKTOP_DISPLAY || ":99";
|
|
@@ -30485,7 +30537,7 @@ function desktopStackHealthy() {
|
|
|
30485
30537
|
const pids = {};
|
|
30486
30538
|
for (const name of ["openbox", "tint2", "x11vnc", "novnc"]) {
|
|
30487
30539
|
try {
|
|
30488
|
-
const pid = Number.parseInt(
|
|
30540
|
+
const pid = Number.parseInt(readFileSync3(`${STATE_DIR}/${name}.pid`, "utf8").trim(), 10);
|
|
30489
30541
|
if (!Number.isFinite(pid)) return false;
|
|
30490
30542
|
process.kill(pid, 0);
|
|
30491
30543
|
pids[name] = pid;
|
|
@@ -30528,7 +30580,7 @@ function runDisplayCmd(bin, args) {
|
|
|
30528
30580
|
return r.stdout?.toString() ?? "";
|
|
30529
30581
|
}
|
|
30530
30582
|
function runDesktopInputCmd(args) {
|
|
30531
|
-
|
|
30583
|
+
mkdirSync3(dirname(INPUT_LOCK_FILE), { recursive: true });
|
|
30532
30584
|
return runDisplayCmd("flock", [
|
|
30533
30585
|
"--exclusive",
|
|
30534
30586
|
"--wait",
|
|
@@ -30603,12 +30655,12 @@ var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
|
30603
30655
|
|
|
30604
30656
|
// src/commands/computer/recording.ts
|
|
30605
30657
|
import { spawn as spawn4 } from "child_process";
|
|
30606
|
-
import { appendFileSync, existsSync as existsSync2, mkdirSync as
|
|
30658
|
+
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
30607
30659
|
import { dirname as dirname2 } from "path";
|
|
30608
30660
|
|
|
30609
30661
|
// src/commands/computer/recording/render.ts
|
|
30610
30662
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
30611
|
-
import { copyFileSync, rmSync as rmSync2, writeFileSync as
|
|
30663
|
+
import { copyFileSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
30612
30664
|
|
|
30613
30665
|
// src/commands/computer/recording/config.ts
|
|
30614
30666
|
var cameraMotion = {
|
|
@@ -31013,7 +31065,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
|
|
|
31013
31065
|
}
|
|
31014
31066
|
const stamp = `${process.pid}-${Date.now()}`;
|
|
31015
31067
|
const cursor = cursorAssets(stamp);
|
|
31016
|
-
|
|
31068
|
+
writeFileSync3(cursor.path, cursorSvg(cursor.size));
|
|
31017
31069
|
const spans = renderedSegmentSpans(segments);
|
|
31018
31070
|
const renderedDuration = spans.length ? spans[spans.length - 1].outputEnd : duration3;
|
|
31019
31071
|
const renderedActions = actionsOnRenderedTimeline(actions, spans);
|
|
@@ -31036,7 +31088,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
|
|
|
31036
31088
|
const concatInputs = segments.map((_, index) => `[v${index}]`).join("");
|
|
31037
31089
|
const filter = `${screenSplitFilter};${filters.join(";")};${concatInputs}concat=n=${segments.length}:v=1:a=0[screen];${cursorFilter}`;
|
|
31038
31090
|
const filterPath = `/tmp/replicas-recording-filter-${stamp}.ffgraph`;
|
|
31039
|
-
|
|
31091
|
+
writeFileSync3(filterPath, filter);
|
|
31040
31092
|
try {
|
|
31041
31093
|
const r = spawnSync2("ffmpeg", [
|
|
31042
31094
|
"-y",
|
|
@@ -31098,7 +31150,7 @@ function clearRecordingState() {
|
|
|
31098
31150
|
}
|
|
31099
31151
|
function recordingStartedAt() {
|
|
31100
31152
|
if (!existsSync2(RECORD_STARTED_AT_FILE)) return null;
|
|
31101
|
-
const startedAt = Number.parseInt(
|
|
31153
|
+
const startedAt = Number.parseInt(readFileSync4(RECORD_STARTED_AT_FILE, "utf8").trim(), 10);
|
|
31102
31154
|
return Number.isFinite(startedAt) ? startedAt : null;
|
|
31103
31155
|
}
|
|
31104
31156
|
function logRecordingAction(action) {
|
|
@@ -31111,7 +31163,7 @@ function logRecordingAction(action) {
|
|
|
31111
31163
|
function readRecordingDimensions() {
|
|
31112
31164
|
if (!existsSync2(RECORD_DIMENSIONS_FILE)) return configuredDesktopDimensions();
|
|
31113
31165
|
try {
|
|
31114
|
-
const dimensions = JSON.parse(
|
|
31166
|
+
const dimensions = JSON.parse(readFileSync4(RECORD_DIMENSIONS_FILE, "utf8"));
|
|
31115
31167
|
const width = dimensions?.width;
|
|
31116
31168
|
const height = dimensions?.height;
|
|
31117
31169
|
if (typeof width === "number" && Number.isFinite(width) && width > 0 && typeof height === "number" && Number.isFinite(height) && height > 0) {
|
|
@@ -31129,7 +31181,7 @@ function isOptionalNumber(value) {
|
|
|
31129
31181
|
}
|
|
31130
31182
|
function readRecordingActions() {
|
|
31131
31183
|
if (!existsSync2(RECORD_ACTIONS_FILE)) return [];
|
|
31132
|
-
return
|
|
31184
|
+
return readFileSync4(RECORD_ACTIONS_FILE, "utf8").split("\n").filter(Boolean).flatMap((line) => {
|
|
31133
31185
|
try {
|
|
31134
31186
|
const value = JSON.parse(line);
|
|
31135
31187
|
if (typeof value !== "object" || value === null) return [];
|
|
@@ -31151,7 +31203,7 @@ function readRecordingActions() {
|
|
|
31151
31203
|
async function computerRecordStartCommand(path6, options) {
|
|
31152
31204
|
ensureServicesRunning();
|
|
31153
31205
|
if (existsSync2(RECORD_PID_FILE)) {
|
|
31154
|
-
const pid = parseInt(
|
|
31206
|
+
const pid = parseInt(readFileSync4(RECORD_PID_FILE, "utf8").trim(), 10);
|
|
31155
31207
|
if (Number.isFinite(pid)) {
|
|
31156
31208
|
let alive2 = false;
|
|
31157
31209
|
try {
|
|
@@ -31163,10 +31215,10 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
31163
31215
|
}
|
|
31164
31216
|
}
|
|
31165
31217
|
const target = resolvePath(path6);
|
|
31166
|
-
|
|
31218
|
+
mkdirSync4(dirname2(target), { recursive: true });
|
|
31167
31219
|
const fps = options.fps ? parseCoord(options.fps, "--fps") : 60;
|
|
31168
31220
|
const { width, height } = configuredDesktopDimensions();
|
|
31169
|
-
|
|
31221
|
+
mkdirSync4(STATE_DIR, { recursive: true });
|
|
31170
31222
|
const rawTarget = `${target}.raw-${Date.now()}.mp4`;
|
|
31171
31223
|
rmSync3(RECORD_ACTIONS_FILE, { force: true });
|
|
31172
31224
|
const child = spawn4("ffmpeg", [
|
|
@@ -31200,17 +31252,17 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
31200
31252
|
], { detached: true, stdio: "ignore" });
|
|
31201
31253
|
child.unref();
|
|
31202
31254
|
if (!child.pid) fail("failed to launch ffmpeg");
|
|
31203
|
-
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31255
|
+
writeFileSync4(RECORD_PID_FILE, String(child.pid));
|
|
31256
|
+
writeFileSync4(RECORD_PATH_FILE, target);
|
|
31257
|
+
writeFileSync4(RECORD_RAW_PATH_FILE, rawTarget);
|
|
31258
|
+
writeFileSync4(RECORD_STARTED_AT_FILE, String(Date.now()));
|
|
31259
|
+
writeFileSync4(RECORD_FPS_FILE, String(fps));
|
|
31260
|
+
writeFileSync4(RECORD_DIMENSIONS_FILE, JSON.stringify({ width, height }));
|
|
31209
31261
|
const startedAt = Date.now();
|
|
31210
31262
|
while (Date.now() - startedAt < 5e3) {
|
|
31211
31263
|
try {
|
|
31212
31264
|
process.kill(child.pid, 0);
|
|
31213
|
-
if (existsSync2(rawTarget) &&
|
|
31265
|
+
if (existsSync2(rawTarget) && statSync2(rawTarget).size > 0) {
|
|
31214
31266
|
console.log(`${target} (recording ready in ${Date.now() - startedAt}ms)`);
|
|
31215
31267
|
return;
|
|
31216
31268
|
}
|
|
@@ -31233,7 +31285,7 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
31233
31285
|
async function computerRecordStopCommand() {
|
|
31234
31286
|
if (!existsSync2(RECORD_PID_FILE) && !existsSync2(RECORD_PATH_FILE)) fail("no recording in progress");
|
|
31235
31287
|
if (existsSync2(RECORD_PID_FILE)) {
|
|
31236
|
-
const pid = parseInt(
|
|
31288
|
+
const pid = parseInt(readFileSync4(RECORD_PID_FILE, "utf8").trim(), 10);
|
|
31237
31289
|
if (!Number.isFinite(pid)) fail("invalid recording pidfile");
|
|
31238
31290
|
try {
|
|
31239
31291
|
process.kill(pid, "SIGINT");
|
|
@@ -31252,9 +31304,9 @@ async function computerRecordStopCommand() {
|
|
|
31252
31304
|
if (alive) fail(`ffmpeg did not finalize recording within 30 seconds (pid ${pid})`);
|
|
31253
31305
|
}
|
|
31254
31306
|
if (existsSync2(RECORD_PATH_FILE)) {
|
|
31255
|
-
const target =
|
|
31256
|
-
const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ?
|
|
31257
|
-
const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(
|
|
31307
|
+
const target = readFileSync4(RECORD_PATH_FILE, "utf8").trim();
|
|
31308
|
+
const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ? readFileSync4(RECORD_RAW_PATH_FILE, "utf8").trim() : target;
|
|
31309
|
+
const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(readFileSync4(RECORD_FPS_FILE, "utf8").trim(), 10) : 60;
|
|
31258
31310
|
const size = readRecordingDimensions();
|
|
31259
31311
|
const actions = readRecordingActions();
|
|
31260
31312
|
if (rawPath !== target) {
|
|
@@ -31346,7 +31398,7 @@ function loadBrandSvg(canvasW, canvasH) {
|
|
|
31346
31398
|
`Brand wallpaper SVG missing at ${path6}. The workspace image is out of date \u2014 \`desktop/brand-wallpaper.svg\` must be installed at $REPLICAS_DESKTOP_TEMPLATES.`
|
|
31347
31399
|
);
|
|
31348
31400
|
}
|
|
31349
|
-
return
|
|
31401
|
+
return readFileSync5(path6, "utf8").replace(/(<svg[^>]*\s)width="\d+"/, `$1width="${canvasW}"`).replace(/(<svg[^>]*\s)height="\d+"/, `$1height="${canvasH}"`);
|
|
31350
31402
|
}
|
|
31351
31403
|
var BRAND_PAD_FRACTION = 0.06;
|
|
31352
31404
|
var SCREENSHOT_CORNER_FRACTION = 0.022;
|
|
@@ -31381,7 +31433,7 @@ ${labels.join("\n")}
|
|
|
31381
31433
|
</svg>`;
|
|
31382
31434
|
}
|
|
31383
31435
|
function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
|
|
31384
|
-
|
|
31436
|
+
writeFileSync5(gridPath, buildGridSvg(width, height, gridSize));
|
|
31385
31437
|
const r = spawnSync3(
|
|
31386
31438
|
"ffmpeg",
|
|
31387
31439
|
[
|
|
@@ -31409,7 +31461,7 @@ function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
|
|
|
31409
31461
|
}
|
|
31410
31462
|
async function computerScreenshotCommand(path6, options = {}) {
|
|
31411
31463
|
const target = resolvePath(path6);
|
|
31412
|
-
|
|
31464
|
+
mkdirSync5(dirname3(target), { recursive: true });
|
|
31413
31465
|
const stamp = `${process.pid}-${Date.now()}`;
|
|
31414
31466
|
const rawPath = `/tmp/replicas-screenshot-${stamp}.raw.png`;
|
|
31415
31467
|
const svgPath = `/tmp/replicas-screenshot-${stamp}.brand.svg`;
|
|
@@ -31441,12 +31493,12 @@ async function computerScreenshotCommand(path6, options = {}) {
|
|
|
31441
31493
|
const shadowMargin = shadowSigma * 3;
|
|
31442
31494
|
const shadowW = width + shadowMargin * 2;
|
|
31443
31495
|
const shadowH = height + shadowMargin * 2;
|
|
31444
|
-
|
|
31445
|
-
|
|
31496
|
+
writeFileSync5(svgPath, loadBrandSvg(canvasW, canvasH));
|
|
31497
|
+
writeFileSync5(
|
|
31446
31498
|
maskPath,
|
|
31447
31499
|
SCREENSHOT_MASK_TEMPLATE.replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
|
|
31448
31500
|
);
|
|
31449
|
-
|
|
31501
|
+
writeFileSync5(
|
|
31450
31502
|
shadowPath,
|
|
31451
31503
|
SHADOW_MASK_TEMPLATE.replace(/__SW__/g, String(shadowW)).replace(/__SH__/g, String(shadowH)).replace(/__M__/g, String(shadowMargin)).replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
|
|
31452
31504
|
);
|
|
@@ -31488,7 +31540,7 @@ async function computerScreenshotCommand(path6, options = {}) {
|
|
|
31488
31540
|
console.log(target);
|
|
31489
31541
|
}
|
|
31490
31542
|
function hashFile(path6) {
|
|
31491
|
-
return
|
|
31543
|
+
return createHash3("sha256").update(readFileSync5(path6)).digest("hex");
|
|
31492
31544
|
}
|
|
31493
31545
|
async function captureStableRawScreenshot(target, options) {
|
|
31494
31546
|
const start = Date.now();
|
|
@@ -31539,7 +31591,7 @@ function recordingMousePosition() {
|
|
|
31539
31591
|
}
|
|
31540
31592
|
async function computerObserveCommand(path6, options = {}) {
|
|
31541
31593
|
const target = resolvePath(path6);
|
|
31542
|
-
|
|
31594
|
+
mkdirSync5(dirname3(target), { recursive: true });
|
|
31543
31595
|
const timeoutMs = options.timeout ? parseCoord(options.timeout, "--timeout") : 3e3;
|
|
31544
31596
|
const stableMs = options.stableMs ? parseCoord(options.stableMs, "--stable-ms") : 600;
|
|
31545
31597
|
const pollMs = options.pollMs ? parseCoord(options.pollMs, "--poll-ms") : 200;
|
|
@@ -31774,7 +31826,7 @@ function browserStateProperties(node) {
|
|
|
31774
31826
|
function readBrowserStateCache(path6) {
|
|
31775
31827
|
let value;
|
|
31776
31828
|
try {
|
|
31777
|
-
value = JSON.parse(
|
|
31829
|
+
value = JSON.parse(readFileSync5(path6, "utf8"));
|
|
31778
31830
|
} catch {
|
|
31779
31831
|
return null;
|
|
31780
31832
|
}
|
|
@@ -32120,7 +32172,7 @@ async function captureBrowserSnapshot(page, options) {
|
|
|
32120
32172
|
visibleTextLength += Math.min(name.length, remaining) + 1;
|
|
32121
32173
|
}
|
|
32122
32174
|
}
|
|
32123
|
-
const revision =
|
|
32175
|
+
const revision = createHash3("sha256").update(JSON.stringify([page.url, entries.map(({ key, semantic }) => [key, semantic])])).digest("hex").slice(0, 16);
|
|
32124
32176
|
const snapshot = {
|
|
32125
32177
|
title: (page.title ?? "").slice(0, 1e3),
|
|
32126
32178
|
url: (page.url ?? "").slice(0, 2e3),
|
|
@@ -32300,7 +32352,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
32300
32352
|
const page = await selectChromePage(options);
|
|
32301
32353
|
const stability = await waitForBrowserStability(page, { timeoutMs, stableMs, pollMs });
|
|
32302
32354
|
const target = resolvePath(path6);
|
|
32303
|
-
|
|
32355
|
+
mkdirSync5(dirname3(target), { recursive: true });
|
|
32304
32356
|
const [{ snapshot, entries }, screenshotResult] = await Promise.all([
|
|
32305
32357
|
captureBrowserSnapshot(page, { textLimit, elementLimit }),
|
|
32306
32358
|
sendChromeCommand(page.webSocketDebuggerUrl, "Page.captureScreenshot", {
|
|
@@ -32311,7 +32363,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
32311
32363
|
]);
|
|
32312
32364
|
const data = screenshotResult.data;
|
|
32313
32365
|
if (typeof data !== "string") fail("Chrome did not return screenshot data");
|
|
32314
|
-
|
|
32366
|
+
writeFileSync5(target, Buffer.from(data, "base64"));
|
|
32315
32367
|
const screenshot = readPngDimensions(target);
|
|
32316
32368
|
const targetId = page.id ?? "unknown";
|
|
32317
32369
|
const cachePath = browserStateCachePath(targetId);
|
|
@@ -32327,8 +32379,8 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
32327
32379
|
changes = { added: diff.added, changed: diff.changed, removed: diff.removed };
|
|
32328
32380
|
}
|
|
32329
32381
|
}
|
|
32330
|
-
|
|
32331
|
-
|
|
32382
|
+
mkdirSync5(STATE_DIR, { recursive: true });
|
|
32383
|
+
writeFileSync5(cachePath, JSON.stringify({ url: snapshot.url, documentId: snapshot.documentId, entries }));
|
|
32332
32384
|
const stableState = isRecord(stability.state) ? stability.state : {};
|
|
32333
32385
|
const state = {
|
|
32334
32386
|
title: snapshot.title,
|
|
@@ -37696,7 +37748,7 @@ if (isAgentMode()) {
|
|
|
37696
37748
|
}
|
|
37697
37749
|
});
|
|
37698
37750
|
const learnings = program.command("learnings").description("Fetch curated org knowledge and propose changes for human review");
|
|
37699
|
-
learnings.command("read").description("Fetch learnings relevant to a task. Enrich the query with codebase specifics, not the raw user request.").requiredOption("-q, --query <query>", "Enriched task description to match against learning triggers").action(async (options) => {
|
|
37751
|
+
learnings.command("read").description("Fetch learnings relevant to a task. Enrich the query with codebase specifics, not the raw user request.").requiredOption("-q, --query <query>", "Enriched task description to match against learning triggers").option("-f, --fresh", "Print full text even for learnings already shown in this session").action(async (options) => {
|
|
37700
37752
|
try {
|
|
37701
37753
|
await learningsReadCommand(options);
|
|
37702
37754
|
} catch (error51) {
|