humanish 0.30.0 → 0.31.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/README.md CHANGED
@@ -262,6 +262,18 @@ you own (a Vercel preview, staging), use an `app-url` subject with
262
262
  only declared subject env names do. `humanish init` scaffolds an example at
263
263
  `humanish/labs/cua-browser.yaml`.
264
264
 
265
+ **Off-app email/SMS verification (`comms`).** When a flow is gated behind an email
266
+ or SMS the app itself sends — a signup verification link, a one-time code, a magic
267
+ link — add a `comms:` block to the lab. Humanish redirects the app's email-API sends
268
+ (via one adopter-named env var, e.g. `RESEND_API_URL`) into a catch **inside** the
269
+ sandbox, so nothing leaves the machine; the persona then opens a synthetic inbox to
270
+ read and click through, and the run bundle gets a digest-only
271
+ `humanish.comms-thread.v1` artifact (from/to/subject/link digests + an OTP count —
272
+ no raw address, link, or code persists). It works on the single-lane clone/local-tree
273
+ route and the concurrent shared-world route, and is vendor-neutral (Resend/SendGrid
274
+ shaped, or a custom profile). See `docs/contracts/schemas.md` for the full `comms:`
275
+ shape.
276
+
265
277
  **Screenshots are full-fidelity by default.** Run bundles live in gitignored
266
278
  `.humanish/`, so the Observer shows exactly what the persona saw — the point of
267
279
  simming your own app. Set `policies.redactScreenshots: true` to persist blurred
@@ -4,7 +4,7 @@ export interface CommsAddress {
4
4
  channel: CommsChannelKind;
5
5
  /** Which lane owns this inbox. */
6
6
  actorId: string;
7
- /** Runtime-only raw address, e.g. patient-07@example.test | +15550137. */
7
+ /** Runtime-only raw address, e.g. user-07@example.test | +15550137. */
8
8
  value: string;
9
9
  /** sha256-short(value) — the only form persisted (redaction.digestText). */
10
10
  digest: string;
package/dist/index.d.ts CHANGED
@@ -17,17 +17,11 @@ export type { FetchLike, OpenAiResponsesProviderOptions } from "./openai-respons
17
17
  export { adapterScoreFailureMessage, applyAdapterScoreFailureToReview, applyBrowserAdapterHooks } from "./adapter-extension.js";
18
18
  export type { BrowserAdapterBackend, BrowserLabAdapterHooks, BrowserLabScoringContext } from "./adapter-extension.js";
19
19
  export type { RedactionHooks } from "./redaction.js";
20
- export { FakeInbox, extractLinks, extractOtpCodes } from "./comms-fake-inbox.js";
20
+ export type { CommsAddress, CommsChannel, CommsChannelKind, CommsMessage, InboundRaw, OutboundMessage } from "./comms-types.js";
21
+ export { FakeInbox } from "./comms-fake-inbox.js";
21
22
  export type { FakeInboxOptions } from "./comms-fake-inbox.js";
22
- export { DEFAULT_EMAIL_PROFILES, genericEmailProfile, sendgridEmailProfile, startEmailCatchServer } from "./comms-email-catch.js";
23
- export type { EmailCatchOptions, EmailCatchServer, EmailSendProfile, NormalizedSend } from "./comms-email-catch.js";
24
- export { DEFAULT_SANDBOX_CATCH_PORT, SANDBOX_CATCH_SCRIPT, collectCommsThread, deployCommsCatch, drainCommsCatch, refreshInboxSurface, routeCapturedSends, writeInboxSurface } from "./comms-sandbox-catch.js";
25
- export type { CommsThreadCollection, DeployCommsCatchOptions, DeployedCommsCatch, InboxSurfaceRecipient, RawCapturedSend } from "./comms-sandbox-catch.js";
26
- export { INBOX_SURFACE_CSP, buildInboxSurface, buildOriginMap, inboxMessageJson, pickVerifyUrl, renderInboxList, renderInboxMessage, renderInboxMessageSynth, rewriteOrigin } from "./comms-inbox.js";
27
- export type { InboxRenderOptions, InboxSurfaceFile, OriginMap } from "./comms-inbox.js";
28
- export { COMMS_THREAD_SCHEMA, buildCommsThreadArtifact } from "./comms-evidence.js";
23
+ export { COMMS_THREAD_SCHEMA } from "./comms-evidence.js";
29
24
  export type { CommsThreadArtifact, CommsThreadEntry } from "./comms-evidence.js";
30
- export type { CommsAddress, CommsChannel, CommsChannelKind, CommsMessage, InboundRaw, OutboundMessage } from "./comms-types.js";
31
25
  export { DESKTOP_RATE, MODEL_RATES, PRICING_SCHEMA, estimateActorCost, estimateDesktopCost } from "./pricing.js";
32
26
  export type { ActorEstimatedCost, DesktopCostEstimate, DesktopRate, ModelRate } from "./pricing.js";
33
27
  export { normalizeCliArgv } from "./argv.js";
package/dist/index.js CHANGED
@@ -7,17 +7,8 @@ export { createE2BDesktopExecutor } from "./e2b-desktop-executor.js";
7
7
  export { loadE2BDesktopModule } from "./e2b-desktop-launch.js";
8
8
  export { DEFAULT_OPENAI_CU_MODEL, OPENAI_RESPONSES_CU_CAPABILITIES, createOpenAiResponsesProvider } from "./openai-responses-cu.js";
9
9
  export { adapterScoreFailureMessage, applyAdapterScoreFailureToReview, applyBrowserAdapterHooks } from "./adapter-extension.js";
10
- // Addressed comms bus (#297): fake email/SMS inboxes + a VENDOR-NEUTRAL email-API catch that
11
- // redirects an API-first app into the fake bus with one env var (Resend-/SendGrid-compatible via
12
- // pluggable profiles, no named vendor dependency). Real (provider-backed) adapters implement the
13
- // same CommsChannel port.
14
- export { FakeInbox, extractLinks, extractOtpCodes } from "./comms-fake-inbox.js";
15
- export { DEFAULT_EMAIL_PROFILES, genericEmailProfile, sendgridEmailProfile, startEmailCatchServer } from "./comms-email-catch.js";
16
- // In-sandbox deployment of the catch + the host-side delivery bridge (the config-block core: the
17
- // listener must live inside the subject sandbox, since 127.0.0.1 from the app is the sandbox loopback).
18
- export { DEFAULT_SANDBOX_CATCH_PORT, SANDBOX_CATCH_SCRIPT, collectCommsThread, deployCommsCatch, drainCommsCatch, refreshInboxSurface, routeCapturedSends, writeInboxSurface } from "./comms-sandbox-catch.js";
19
- export { INBOX_SURFACE_CSP, buildInboxSurface, buildOriginMap, inboxMessageJson, pickVerifyUrl, renderInboxList, renderInboxMessage, renderInboxMessageSynth, rewriteOrigin } from "./comms-inbox.js";
20
- export { COMMS_THREAD_SCHEMA, buildCommsThreadArtifact } from "./comms-evidence.js";
10
+ export { FakeInbox } from "./comms-fake-inbox.js";
11
+ export { COMMS_THREAD_SCHEMA } from "./comms-evidence.js";
21
12
  export { DESKTOP_RATE, MODEL_RATES, PRICING_SCHEMA, estimateActorCost, estimateDesktopCost } from "./pricing.js";
22
13
  export { normalizeCliArgv } from "./argv.js";
23
14
  export { CODEX_APP_SERVER_UI_SCHEMA, startCodexAppServerUi } from "./codex-app-server-ui.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  Date: 2026-06-02 (current-state note updated 2026-07-14)
4
4
 
5
5
  Status: reference map for the major contracts shipped through source version
6
- `0.30.0`; it is not an exhaustive inventory of command/result envelopes. Exported types,
6
+ `0.31.0`; it is not an exhaustive inventory of command/result envelopes. Exported types,
7
7
  schema constants, parsers, and validators in `src/` are authoritative. Rows
8
8
  marked "reserved" name layering intent only — no code emits or validates them
9
9
  yet. Do not emit a reserved schema.
@@ -49,6 +49,7 @@ workflow without leaking private upstream truth into core.
49
49
  | Adapter score | `humanish.adapter-score.v1` (`RunBundle.adapterScore`; namespaced; route-specific acceptance semantics) | see Product-Adapter Extension Seam below |
50
50
  | Adapter artifact | `humanish.adapter-artifact.v1` (`RunBundle.adapterArtifacts[]`; namespaced; local relative proof references) | see Product-Adapter Extension Seam below |
51
51
  | Shared-world evidence | `humanish.shared-world.v1` (additive `RunBundle.sharedWorld` + `RunBundle.attributionClass`; `topologyMode: sequential \| concurrent`) | see Shared-World Evidence below |
52
+ | Comms thread | `humanish.comms-thread.v1` (off-app email/SMS the app sent, captured; a `kind: log` run-dir artifact of DIGESTS only — from/to/subject/link digests + an OTP count, never raw) | see `comms` under Lab Manifest |
52
53
  | Serve result | `humanish.serve-result.v1` (`src/observer-serve.ts` is authoritative) | none (command result envelope; see Serve Result below) |
53
54
  | Serve control plane | reserved (`/_humanish/api/*` answers `501` `HUMANISH_SERVE_CONTROL_PLANE_DISABLED` in v1) | none |
54
55
 
@@ -242,6 +243,22 @@ A lab is a composition over code primitives, not a hardcoded kind:
242
243
  only command-scoped). The scripted-browser route is loopback-only and rejects
243
244
  `redactScreenshots: true` (blur unimplemented there) and
244
245
  `allowPublicTargets: true` fail-closed rather than ignoring them.
246
+ - `comms` (clone/local-tree + shared-world computer-use routes; #297): off-app
247
+ email/SMS the app itself SENDS, made a persona-driven testable surface.
248
+ `comms.email` = `{ kind: fake, injectEnv, port?, recipients?, linkOrigin? }`.
249
+ `injectEnv` is the ADOPTER-NAMED env var the app reads for its email-API base
250
+ URL (e.g. `RESEND_API_URL`); the harness sets it to an in-sandbox catch (so it
251
+ is NOT declared in `subject.env`) that captures the app's sends without touching
252
+ the internet. `kind` must be `fake` (`real`/provider-backed is rejected until
253
+ implemented); `port` ≤ 65534 (the catch reserves `port+1` for the read-only
254
+ inbox listener the shared-world route getHost-exposes); `recipients[]` =
255
+ `{ lane, address? }` declare the literal address each lane's app emails (so the
256
+ drain can match it, and the persona is told an inbox URL to read + click);
257
+ `linkOrigin` is an optional operator-declared origin the app bakes into links
258
+ when it differs from the serve origin. Captured mail is drained into a
259
+ digest-only `humanish.comms-thread.v1` artifact (from/to/subject/link DIGESTS +
260
+ an OTP COUNT — no raw address/link/code persists). Requires `python3` in the
261
+ subject sandbox (the stock E2B desktop template has it).
245
262
 
246
263
  Lab backends report results in their own schemas (`humanish.run-result.v1`,
247
264
  `humanish.oss-lab-result.v1`, `humanish.oss-meta-lab-result.v1`,
@@ -16,7 +16,7 @@ Humanish should be the open-source CLI that lets a maintainer ask:
16
16
  The answer should be observable, verifiable, public-safe, and easy to turn into
17
17
  actionable feedback.
18
18
 
19
- ## Current Program Truth (source `0.30.0`)
19
+ ## Current Program Truth (source `0.31.0`)
20
20
 
21
21
  The package source and repository implementation in this tree agree on these
22
22
  points:
@@ -2,7 +2,7 @@
2
2
 
3
3
  Status: public-safe contributor and agent ramp.
4
4
 
5
- Package/source version in this tree: `0.30.0` (2026-08-04). The containment boundary introduced in
5
+ Package/source version in this tree: `0.31.0` (2026-08-04). The containment boundary introduced in
6
6
  `0.15.1` remains in force: managed run and output paths bind to validated
7
7
  physical filesystem identities, and stored provider IDs are evidence, not
8
8
  cleanup authority. The bundled OSS meta-lab is dry-run only until
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanish",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "Open-source-safe CLI for persona simulation, observer review, and public-safe feedback drafts.",
5
5
  "author": "Daniel G Wilson <daniel@danielgwilson.com>",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: humanish
3
- description: Install and configure Humanish CLI in a JavaScript app as an open-source-safe persona simulation harness. Use when an agent needs to add humanish, run safe first setup, create synthetic personas or scenarios, configure env var names without values, run verification and Observer commands, or draft public-safe feedback issues without GitHub mutation.
3
+ description: Install and configure Humanish CLI in a JavaScript app as an open-source-safe persona simulation harness. Use when an agent needs to add humanish, run safe first setup, create synthetic personas or scenarios, configure env var names without values, capture the email or SMS an app sends so a persona can complete an email-gated flow (e.g. a signup verification link or one-time code), run verification and Observer commands, or draft public-safe feedback issues without GitHub mutation.
4
4
  ---
5
5
 
6
6
  # Humanish CLI
@@ -166,6 +166,33 @@ npx humanish watch first-run
166
166
  npx humanish lab run first-run --json --no-open
167
167
  ```
168
168
 
169
+ ### Off-app email/SMS verification (comms)
170
+
171
+ When a flow is gated behind an email or SMS the app itself SENDS — a signup
172
+ verification link, a one-time code, a magic link — add a `comms:` block. The
173
+ harness redirects the app's email-API sends into a catch INSIDE the sandbox (no
174
+ mail leaves the machine), gives the persona a synthetic inbox to open and click
175
+ through, and writes a digest-only `humanish.comms-thread.v1` evidence artifact (no
176
+ raw address/link/code persists). Reach for this whenever a persona must read mail
177
+ the app sent it to finish a step.
178
+
179
+ ```yaml
180
+ comms:
181
+ email:
182
+ injectEnv: RESEND_API_URL # adopter-named: whatever env var YOUR app reads for its
183
+ # email-API base URL. The harness sets it to the in-sandbox
184
+ # catch — do NOT also list it in subject.env.
185
+ recipients:
186
+ - lane: lane-01 # the actor lane that signs up
187
+ address: user@example.test # the literal address the app emails (what the persona uses)
188
+ ```
189
+
190
+ The app keeps calling its email API normally (Resend/SendGrid-shaped, or a custom
191
+ profile); only the base URL is redirected. Works on the clone/local-tree route and
192
+ the concurrent shared-world route. It needs `python3` in the subject sandbox (the
193
+ stock E2B desktop has it). See `docs/contracts/schemas.md` for the full `comms:`
194
+ shape and `humanish <cmd> --help` for run flags — this skill does not restate them.
195
+
169
196
  ## First Proof Run
170
197
 
171
198
  Run the no-credentials path first. This proves Humanish artifact plumbing, not