@wibeco/bridge 0.2.10 → 0.2.12
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.
|
@@ -19,15 +19,71 @@ import {
|
|
|
19
19
|
startPresenceSession,
|
|
20
20
|
stopPresenceSession,
|
|
21
21
|
updatePresenceSession
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-JXH47J5I.js";
|
|
23
23
|
|
|
24
24
|
// src/cli/commands.ts
|
|
25
25
|
import { access, cp, mkdir, readFile, writeFile } from "fs/promises";
|
|
26
26
|
import { homedir, hostname } from "os";
|
|
27
|
-
import { join, resolve } from "path";
|
|
27
|
+
import { basename, join, resolve } from "path";
|
|
28
28
|
import { fileURLToPath } from "url";
|
|
29
29
|
import { execFile } from "child_process";
|
|
30
30
|
var ADAPTERS = ["cursor", "claude-code", "codex"];
|
|
31
|
+
var MAX_SCREENSHOT_BYTES = 5 * 1024 * 1024;
|
|
32
|
+
function screenshotMimeType(bytes) {
|
|
33
|
+
if ([137, 80, 78, 71, 13, 10, 26, 10].every(
|
|
34
|
+
(byte, index) => bytes[index] === byte
|
|
35
|
+
)) {
|
|
36
|
+
return "image/png";
|
|
37
|
+
}
|
|
38
|
+
if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
|
|
39
|
+
return "image/jpeg";
|
|
40
|
+
}
|
|
41
|
+
if (new TextDecoder().decode(bytes.slice(0, 4)) === "RIFF" && new TextDecoder().decode(bytes.slice(8, 12)) === "WEBP") {
|
|
42
|
+
return "image/webp";
|
|
43
|
+
}
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
async function uploadProgressScreenshot(screenshotPath, altText, credential, cwd) {
|
|
47
|
+
try {
|
|
48
|
+
const resolvedPath = resolve(cwd, screenshotPath);
|
|
49
|
+
const bytes = await readFile(resolvedPath);
|
|
50
|
+
if (!bytes.length || bytes.length > MAX_SCREENSHOT_BYTES) {
|
|
51
|
+
return {
|
|
52
|
+
warning: "Screenshot skipped: image must be between 1 byte and 5 MB."
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const mimeType = screenshotMimeType(bytes);
|
|
56
|
+
if (!mimeType) {
|
|
57
|
+
return {
|
|
58
|
+
warning: "Screenshot skipped: only PNG, JPEG, and WebP are supported."
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const form = new FormData();
|
|
62
|
+
form.set(
|
|
63
|
+
"screenshot",
|
|
64
|
+
new Blob([new Uint8Array(bytes)], { type: mimeType }),
|
|
65
|
+
basename(resolvedPath)
|
|
66
|
+
);
|
|
67
|
+
form.set("alt_text", altText);
|
|
68
|
+
const response = await fetch(`${credential.appUrl}/api/artifacts`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { authorization: `Bearer ${credential.accessToken}` },
|
|
71
|
+
body: form,
|
|
72
|
+
signal: AbortSignal.timeout(1e4)
|
|
73
|
+
});
|
|
74
|
+
const body = await response.json().catch(() => ({}));
|
|
75
|
+
if (!response.ok || typeof body.artifact_id !== "string") {
|
|
76
|
+
return {
|
|
77
|
+
warning: `Screenshot skipped: ${typeof body.error === "string" ? body.error : `upload failed with status ${response.status}`}.`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { artifactId: body.artifact_id };
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
warning: `Screenshot skipped: ${error instanceof Error ? error.message : "upload failed"}.`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
31
87
|
async function setupCommand(requestedAdapter, options = {}) {
|
|
32
88
|
const cwd = options.cwd ?? process.cwd();
|
|
33
89
|
const expectedRepository = options.expectedRepository ? normalizeGitHubRepository(options.expectedRepository) : void 0;
|
|
@@ -352,6 +408,10 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
352
408
|
if (title && title.length > 120) {
|
|
353
409
|
throw new Error("Progress title must be 120 characters or fewer.");
|
|
354
410
|
}
|
|
411
|
+
const screenshotAlt = options.screenshotAlt?.trim() || (title ? `${title} screenshot` : "Agent update screenshot");
|
|
412
|
+
if (screenshotAlt.length > 240) {
|
|
413
|
+
throw new Error("Screenshot alt text must be 240 characters or fewer.");
|
|
414
|
+
}
|
|
355
415
|
const phases = [
|
|
356
416
|
"planning",
|
|
357
417
|
"implementing",
|
|
@@ -371,6 +431,12 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
371
431
|
projectConfig.adapter,
|
|
372
432
|
cwd
|
|
373
433
|
);
|
|
434
|
+
const screenshot = options.screenshot?.trim() ? await uploadProgressScreenshot(
|
|
435
|
+
options.screenshot.trim(),
|
|
436
|
+
screenshotAlt,
|
|
437
|
+
credential,
|
|
438
|
+
cwd
|
|
439
|
+
) : {};
|
|
374
440
|
const event = createHookEvent({
|
|
375
441
|
source: projectConfig.adapter,
|
|
376
442
|
kind: "progress.shared",
|
|
@@ -380,6 +446,7 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
380
446
|
...title ? { title } : {},
|
|
381
447
|
...options.phase ? { phase: options.phase } : {},
|
|
382
448
|
...options.confidence !== void 0 ? { confidence: options.confidence } : {},
|
|
449
|
+
...screenshot.artifactId ? { artifact_id: screenshot.artifactId } : {},
|
|
383
450
|
...workingTree ? {
|
|
384
451
|
paths: workingTree.paths,
|
|
385
452
|
lines_added: workingTree.linesAdded,
|
|
@@ -399,7 +466,7 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
399
466
|
}).capture(event);
|
|
400
467
|
return {
|
|
401
468
|
exitCode: result.error ? 1 : 0,
|
|
402
|
-
message: result.error ? `Progress was queued; delivery failed: ${result.error}` : `Shared progress with Wibe; ${result.remaining} event(s) queued
|
|
469
|
+
message: result.error ? `Progress was queued; delivery failed: ${result.error}` : `Shared progress with Wibe; ${result.remaining} event(s) queued.${screenshot.warning ? ` ${screenshot.warning}` : ""}`
|
|
403
470
|
};
|
|
404
471
|
}
|
|
405
472
|
async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
@@ -389,6 +389,7 @@ function toEnvelope(event, options) {
|
|
|
389
389
|
paths,
|
|
390
390
|
phase: event.metadata.phase,
|
|
391
391
|
confidence: event.metadata.confidence,
|
|
392
|
+
artifact_id: typeof event.metadata.artifact_id === "string" ? event.metadata.artifact_id : void 0,
|
|
392
393
|
lines_added: typeof event.metadata.lines_added === "number" ? event.metadata.lines_added : void 0,
|
|
393
394
|
lines_deleted: typeof event.metadata.lines_deleted === "number" ? event.metadata.lines_deleted : void 0
|
|
394
395
|
} : event.kind === "file.changed" ? {
|
package/dist/cli.js
CHANGED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
setupCommand,
|
|
7
7
|
shareProgressCommand,
|
|
8
8
|
statusCommand
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7AU52DBJ.js";
|
|
10
10
|
import {
|
|
11
11
|
runPresenceHeartbeat
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JXH47J5I.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
15
|
var HELP = `wibe-bridge <command>
|
|
@@ -21,7 +21,7 @@ Commands:
|
|
|
21
21
|
Use --reauthorize only to replace a rejected or revoked device token.
|
|
22
22
|
status
|
|
23
23
|
emit --adapter <name> --event <hook-name> (JSON payload on stdin)
|
|
24
|
-
share-progress --summary <20-55 words> [--title <title>] [--phase <phase>] [--confidence <0-1>]
|
|
24
|
+
share-progress --summary <20-55 words> [--title <title>] [--phase <phase>] [--confidence <0-1>] [--screenshot <path>] [--screenshot-alt <text>]
|
|
25
25
|
doctor [--repository <owner/repo>]`;
|
|
26
26
|
async function main() {
|
|
27
27
|
const [command, ...args] = process.argv.slice(2);
|
|
@@ -54,7 +54,9 @@ async function main() {
|
|
|
54
54
|
summary: option(args, "--summary"),
|
|
55
55
|
title: option(args, "--title"),
|
|
56
56
|
phase: option(args, "--phase"),
|
|
57
|
-
confidence: confidence === void 0 ? void 0 : Number(confidence)
|
|
57
|
+
confidence: confidence === void 0 ? void 0 : Number(confidence),
|
|
58
|
+
screenshot: option(args, "--screenshot"),
|
|
59
|
+
screenshotAlt: option(args, "--screenshot-alt")
|
|
58
60
|
});
|
|
59
61
|
} else if (command === "_presence-heartbeat") {
|
|
60
62
|
parseAdapter(option(args, "--adapter"));
|
package/dist/codex-hook.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -7,7 +7,10 @@ alwaysApply: true
|
|
|
7
7
|
|
|
8
8
|
- This repository is connected to Wibe project `${WIBE_PROJECT_ID}`.
|
|
9
9
|
- For most tasks, publish one update only after the requested outcome is complete. Do not publish plans, routine progress, or separate updates for editing, testing, committing, or pushing.
|
|
10
|
-
-
|
|
10
|
+
- For text-only outcomes, use `wibe_share_progress` with phase `shipped` at completion. Publish earlier only with phase `blocked` when a material blocker leaves the task unfinished.
|
|
11
11
|
- Write one self-contained paragraph of 20–55 words in past tense. Lead with what now works, then explain the user or team impact and meaningful validation. Mention important limitations when present.
|
|
12
12
|
- Describe the outcome, not the agent’s process. Never include first-person narration, prompts, source code, secrets, raw commands, routine tool calls, filenames, line counts, praise, hype, or speculation; Wibe displays code and file changes separately.
|
|
13
|
+
- Bias frontend outcomes toward visual evidence without asking for per-task approval. For UI components, pages, styling, responsive behavior, interactions, and visual fixes, attach one screenshot when the app or preview is already runnable. Prefer a screenshot already made during visual QA; otherwise capture the clearest final state.
|
|
14
|
+
- Skip screenshots for backend, infrastructure, documentation, refactors, and non-visual frontend logic. Never launch or repair an app solely for Wibe, and omit the image when navigation needs manual authentication, the state contains sensitive data, visual validation is blocked, or the project has visual updates disabled.
|
|
15
|
+
- When a screenshot is available, do not call `wibe_share_progress`. Instead run `npx --yes --package @wibeco/bridge@latest wibe share-progress --summary "<summary>" --phase <shipped|blocked> --screenshot "<path>"` so the local bridge uploads the image and publishes the outcome together.
|
|
13
16
|
- If the Wibe MCP tool is unavailable, run `npx --yes --package @wibeco/bridge@latest wibe share-progress --summary "<summary>" --phase <shipped|blocked>`.
|