humanish 0.22.0 → 0.24.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/comms-email-catch.js +1 -1
- package/dist/{comms-faux-inbox.d.ts → comms-fake-inbox.d.ts} +5 -5
- package/dist/{comms-faux-inbox.js → comms-fake-inbox.js} +9 -6
- package/dist/comms-fake-inbox.js.map +1 -0
- package/dist/comms-sandbox-catch.d.ts +1 -1
- package/dist/comms-sandbox-catch.js +1 -1
- package/dist/comms-types.d.ts +4 -4
- package/dist/comms-types.js +1 -1
- package/dist/concurrent-shared-world-lab.js +1 -1
- package/dist/cua-actor-lab.js +21 -2
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/lab-config.d.ts +27 -0
- package/dist/lab-config.js +61 -0
- package/dist/lab-config.js.map +1 -1
- package/docs/architecture/external-public-shared-world.md +1 -1
- package/docs/contracts/schemas.md +1 -1
- package/docs/goals/current.md +1 -1
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
- package/dist/comms-faux-inbox.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// A VENDOR-NEUTRAL loopback catch server for email-send APIs (#297). An app hardwired to a hosted
|
|
2
|
-
// email provider is redirected into the
|
|
2
|
+
// email provider is redirected into the fake bus with ONE env var and no code change: point the app's
|
|
3
3
|
// API base URL at this server. The catch does not depend on, or name itself after, any one vendor —
|
|
4
4
|
// it normalizes each provider's distinct wire shape (Resend's flat body, SendGrid's nested
|
|
5
5
|
// personalizations, Postmark's TitleCase, a custom app's own JSON) to one shape via pluggable
|
|
@@ -6,7 +6,7 @@ export declare function extractLinks(body: string): string[];
|
|
|
6
6
|
* "verification code 8A3F2K") are high-precision and preferred; if none are labeled, fall back to an
|
|
7
7
|
* isolated 4–8 digit run (a bare OTP). Pure; tokens are runtime-only literal-scrub targets. */
|
|
8
8
|
export declare function extractOtpCodes(body: string): string[];
|
|
9
|
-
export interface
|
|
9
|
+
export interface FakeInboxOptions {
|
|
10
10
|
/** "email" (default) or "sms" — the address shape + surface differ; machinery is identical. */
|
|
11
11
|
channel?: CommsChannelKind;
|
|
12
12
|
/** Email domain for minted addresses. Default example.test (an RFC 6761 reserved, unroutable test
|
|
@@ -15,17 +15,17 @@ export interface FauxInboxOptions {
|
|
|
15
15
|
/** Injected clock (ms) for deterministic tests. Default Date.now. */
|
|
16
16
|
now?: () => number;
|
|
17
17
|
}
|
|
18
|
-
/** The in-process
|
|
19
|
-
export declare class
|
|
18
|
+
/** The in-process fake adapter. Implements the same CommsChannel port a real provider adapter would. */
|
|
19
|
+
export declare class FakeInbox implements CommsChannel {
|
|
20
20
|
readonly channel: CommsChannelKind;
|
|
21
|
-
readonly kind: "
|
|
21
|
+
readonly kind: "fake";
|
|
22
22
|
private readonly domain;
|
|
23
23
|
private readonly clock;
|
|
24
24
|
private readonly byActor;
|
|
25
25
|
private readonly byValue;
|
|
26
26
|
private readonly queues;
|
|
27
27
|
private counter;
|
|
28
|
-
constructor(options?:
|
|
28
|
+
constructor(options?: FakeInboxOptions);
|
|
29
29
|
provision(actorId: string): Promise<CommsAddress>;
|
|
30
30
|
private route;
|
|
31
31
|
send(message: OutboundMessage): Promise<CommsMessage>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
// The
|
|
1
|
+
// The FAKE in-process email/SMS bus (#297 Stage 2). "Fake" in the precise test-double sense (Fowler):
|
|
2
|
+
// a working, in-memory implementation of the CommsChannel port that takes a production shortcut — the
|
|
3
|
+
// same slot as Kubernetes' `fake` clientset, distinct from a mock/stub. Deterministic, $0, offline,
|
|
4
|
+
// public-safe: a
|
|
2
5
|
// message an app-under-test "sends" (via an ingress like the vendor-neutral email catch) is routed to the
|
|
3
6
|
// addressed actor inbox and read back through the same CommsChannel port a real provider adapter
|
|
4
7
|
// would implement. Nothing leaves the process. See comms-types.ts for the port + public-safety notes.
|
|
@@ -73,10 +76,10 @@ function smsAddressFor(actorId) {
|
|
|
73
76
|
const digits = digestText(actorId, 16).replace(/[a-f]/g, (c) => String(c.charCodeAt(0) % 10)).slice(0, 7);
|
|
74
77
|
return `+1555${digits}`;
|
|
75
78
|
}
|
|
76
|
-
/** The in-process
|
|
77
|
-
export class
|
|
79
|
+
/** The in-process fake adapter. Implements the same CommsChannel port a real provider adapter would. */
|
|
80
|
+
export class FakeInbox {
|
|
78
81
|
channel;
|
|
79
|
-
kind = "
|
|
82
|
+
kind = "fake";
|
|
80
83
|
domain;
|
|
81
84
|
clock;
|
|
82
85
|
byActor = new Map();
|
|
@@ -95,7 +98,7 @@ export class FauxInbox {
|
|
|
95
98
|
const value = this.channel === "sms" ? smsAddressFor(actorId) : `${sanitizeLocalPart(actorId)}@${this.domain}`;
|
|
96
99
|
// Address collision guard: two distinct actor ids can sanitize to the same local part. Reuse the
|
|
97
100
|
// existing inbox rather than resetting its queue (which would drop already-delivered mail). Both
|
|
98
|
-
// actors then share it — a
|
|
101
|
+
// actors then share it — a fake-world edge; declare distinct addresses to avoid it.
|
|
99
102
|
const prior = this.byValue.get(value.toLowerCase());
|
|
100
103
|
if (prior) {
|
|
101
104
|
this.byActor.set(actorId, prior);
|
|
@@ -154,4 +157,4 @@ export class FauxInbox {
|
|
|
154
157
|
return [...this.byActor.values()];
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
|
-
//# sourceMappingURL=comms-
|
|
160
|
+
//# sourceMappingURL=comms-fake-inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comms-fake-inbox.js","sourceRoot":"","sources":["../src/comms-fake-inbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,7 +57,7 @@ export declare function drainCommsCatch(desktop: E2BDesktopSandbox, deployed: Pi
|
|
|
57
57
|
}>;
|
|
58
58
|
/**
|
|
59
59
|
* Parse drained raw sends with the host profiles and route them into the CommsChannel (the host-side
|
|
60
|
-
*
|
|
60
|
+
* FakeInbox). Returns the number of inbox deliveries made. Same profiles as the host catch, so the
|
|
61
61
|
* in-sandbox and in-process routes normalize identically.
|
|
62
62
|
*/
|
|
63
63
|
export declare function routeCapturedSends(sends: RawCapturedSend[], channel: CommsChannel, profiles?: EmailSendProfile[]): Promise<number>;
|
|
@@ -126,7 +126,7 @@ export async function drainCommsCatch(desktop, deployed, cursor = 0, requestTime
|
|
|
126
126
|
}
|
|
127
127
|
/**
|
|
128
128
|
* Parse drained raw sends with the host profiles and route them into the CommsChannel (the host-side
|
|
129
|
-
*
|
|
129
|
+
* FakeInbox). Returns the number of inbox deliveries made. Same profiles as the host catch, so the
|
|
130
130
|
* in-sandbox and in-process routes normalize identically.
|
|
131
131
|
*/
|
|
132
132
|
export async function routeCapturedSends(sends, channel, profiles = DEFAULT_EMAIL_PROFILES) {
|
package/dist/comms-types.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface CommsMessage {
|
|
|
18
18
|
/** Resolved recipient inboxes this message was delivered to. */
|
|
19
19
|
to: CommsAddress[];
|
|
20
20
|
subject?: string;
|
|
21
|
-
/** Runtime-only for real; local-only for
|
|
21
|
+
/** Runtime-only for real; local-only for fake (never a share path without redaction — #108). */
|
|
22
22
|
body: string;
|
|
23
23
|
/** Actionable links extracted from the body (magic-link / invite / reset). Runtime-only. */
|
|
24
24
|
links: string[];
|
|
@@ -43,12 +43,12 @@ export interface InboundRaw {
|
|
|
43
43
|
body: string;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* The port.
|
|
47
|
-
* real (network) adapter fits without changing callers; the
|
|
46
|
+
* The port. Fake (in-process) + real-email + real-sms adapters implement it identically. Async so a
|
|
47
|
+
* real (network) adapter fits without changing callers; the fake adapter just resolves immediately.
|
|
48
48
|
*/
|
|
49
49
|
export interface CommsChannel {
|
|
50
50
|
readonly channel: CommsChannelKind;
|
|
51
|
-
readonly kind: "
|
|
51
|
+
readonly kind: "fake" | "real";
|
|
52
52
|
/** Mint/allocate an inbox for an actor (address auto-generated). Idempotent per actor. */
|
|
53
53
|
provision(actorId: string): Promise<CommsAddress>;
|
|
54
54
|
/** Route a composed message from one actor to addressed inboxes. Returns the delivered record. */
|
package/dist/comms-types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The addressed message bus (#297) — the seam that makes "off-app" comms (email/SMS the persona
|
|
2
2
|
// actually lives in) a first-class, persona-driven testable surface. A single port, addressed by
|
|
3
|
-
// actor;
|
|
3
|
+
// actor; fake (in-process) and real (provider-backed) adapters implement it identically, so the
|
|
4
4
|
// persona surface + evidence writer consume it without knowing which is behind it.
|
|
5
5
|
//
|
|
6
6
|
// PUBLIC-SAFETY: raw address values, message bodies, links, and codes are RUNTIME-ONLY. Only the
|
|
@@ -919,7 +919,7 @@ export async function runConcurrentSharedWorld(options) {
|
|
|
919
919
|
//
|
|
920
920
|
// TEMPORARY SHIM (tracked by #296): this CDP URL-relay handoff — reading the host's /lobby/CODE off
|
|
921
921
|
// its own browser and threading it into the follower missions — is a temporary coordination shim.
|
|
922
|
-
// It is to be augmented/replaced by the actor message bus (
|
|
922
|
+
// It is to be augmented/replaced by the actor message bus (fake SMS/email invite) in #297: the
|
|
923
923
|
// human-realistic version is the HOST SENDING the invite link and followers RECEIVING and tapping
|
|
924
924
|
// it, rather than the orchestrator relaying the code out-of-band.
|
|
925
925
|
const lobbyCodeLatch = deferred();
|
package/dist/cua-actor-lab.js
CHANGED
|
@@ -31,6 +31,7 @@ import { CHROMIUM_EVIDENCE_HYGIENE_FLAGS, chromiumEvidenceProfilePreferencesJson
|
|
|
31
31
|
import { DEFAULT_OPENAI_CU_MODEL } from "./openai-responses-cu.js";
|
|
32
32
|
import { createDesktopSandbox, loadE2BDesktopModule } from "./e2b-desktop-launch.js";
|
|
33
33
|
import { probeUrl, readDetachedLog, runDetachedStep, startDetachedProcess } from "./e2b-detached.js";
|
|
34
|
+
import { DEFAULT_SANDBOX_CATCH_PORT, deployCommsCatch } from "./comms-sandbox-catch.js";
|
|
34
35
|
import { DEFAULT_DEVICE_PRESET, isDevicePresetName, resolveDevicePreset } from "./device-presets.js";
|
|
35
36
|
import { cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, MAX_CUA_LANES, subjectStateInvalidReason } from "./lab-config.js";
|
|
36
37
|
import { mapWithConcurrency } from "./concurrency.js";
|
|
@@ -987,6 +988,15 @@ export async function runCuaLane(spec, deps) {
|
|
|
987
988
|
const { config, appUrl, cloneRoute, localTreeRoute, serve, subjectRepo, subjectEnvNames } = deps;
|
|
988
989
|
const targetUrl = spec.targetUrl ?? appUrl;
|
|
989
990
|
const env = deps.env;
|
|
991
|
+
// Off-app comms (#297): on an in-sandbox subject route, redirect the app's email-API sends into an
|
|
992
|
+
// in-sandbox catch (loopback) so its verification mail is CAPTURED, not sent to the internet. Gated
|
|
993
|
+
// ENTIRELY on config.comms — no comms declared → zero change. The base-URL env is injected at
|
|
994
|
+
// sandbox-create (below, so the app reads it at boot); the catch is started right after create.
|
|
995
|
+
const commsEmail = (cloneRoute || localTreeRoute) ? config.comms?.email : undefined;
|
|
996
|
+
const commsPort = commsEmail ? (commsEmail.port ?? DEFAULT_SANDBOX_CATCH_PORT) : undefined;
|
|
997
|
+
const commsEnv = commsEmail && commsPort !== undefined
|
|
998
|
+
? { [commsEmail.injectEnv]: `http://127.0.0.1:${commsPort}` }
|
|
999
|
+
: {};
|
|
990
1000
|
const warnings = [];
|
|
991
1001
|
const screenshots = [];
|
|
992
1002
|
const writeScreenshot = makeLaneWriteScreenshot(deps.artifactRoot, spec, screenshots);
|
|
@@ -1055,8 +1065,8 @@ export async function runCuaLane(spec, deps) {
|
|
|
1055
1065
|
},
|
|
1056
1066
|
// Env placement per the doctrine: the ACTOR's key never enters the sandbox (the model drives
|
|
1057
1067
|
// from outside). The SUBJECT's declared env NAMES are provisioned here on the clone route.
|
|
1058
|
-
...(subjectEnvNames.length > 0
|
|
1059
|
-
? { envs: Object.fromEntries(subjectEnvNames.map((name) => [name, env[name]])) }
|
|
1068
|
+
...(subjectEnvNames.length > 0 || Object.keys(commsEnv).length > 0
|
|
1069
|
+
? { envs: { ...Object.fromEntries(subjectEnvNames.map((name) => [name, env[name]])), ...commsEnv } }
|
|
1060
1070
|
: {}),
|
|
1061
1071
|
resolution: spec.resolution,
|
|
1062
1072
|
dpi: 96,
|
|
@@ -1068,6 +1078,15 @@ export async function runCuaLane(spec, deps) {
|
|
|
1068
1078
|
if (deps.hooks.prepareDesktop) {
|
|
1069
1079
|
await deps.hooks.prepareDesktop(desktop, { laneId: spec.laneId, laneIndex: spec.laneIndex, laneCount: deps.laneCount });
|
|
1070
1080
|
}
|
|
1081
|
+
// Start the in-sandbox email catch BEFORE the subject serve, so the app's send-API base URL (injected
|
|
1082
|
+
// into its env at create) resolves the moment it boots. A comms-declared lab that can't stand the
|
|
1083
|
+
// catch up is a setup failure (fail closed) rather than silently sending real mail.
|
|
1084
|
+
if (commsEmail && commsPort !== undefined) {
|
|
1085
|
+
const deployedComms = await deployCommsCatch(desktop, { port: commsPort, requestTimeoutMs: deps.requestTimeoutMs });
|
|
1086
|
+
if (!deployedComms.ready) {
|
|
1087
|
+
throw new Error(`comms email catch did not become ready on 127.0.0.1:${commsPort} in the subject sandbox`);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1071
1090
|
// Per-lane geometry assertion (fail-closed) — the device claim is verified in-sandbox.
|
|
1072
1091
|
const screenGeometry = await inspectDesktopScreenGeometry({
|
|
1073
1092
|
desktop,
|