humanish 0.0.1 → 0.15.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.
Files changed (196) hide show
  1. package/AGENTS.md +77 -0
  2. package/CONTRIBUTING.md +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +435 -8
  5. package/SECURITY.md +34 -0
  6. package/dist/actor-contract.d.ts +107 -0
  7. package/dist/actor-contract.js +286 -0
  8. package/dist/actor-contract.js.map +1 -0
  9. package/dist/actor-registry.d.ts +73 -0
  10. package/dist/actor-registry.js +93 -0
  11. package/dist/actor-registry.js.map +1 -0
  12. package/dist/adapter-extension.d.ts +54 -0
  13. package/dist/adapter-extension.js +214 -0
  14. package/dist/adapter-extension.js.map +1 -0
  15. package/dist/argv.d.ts +1 -0
  16. package/dist/argv.js +8 -0
  17. package/dist/argv.js.map +1 -0
  18. package/dist/artifact-reference.d.ts +22 -0
  19. package/dist/artifact-reference.js +47 -0
  20. package/dist/artifact-reference.js.map +1 -0
  21. package/dist/browser-evidence-hygiene.d.ts +7 -0
  22. package/dist/browser-evidence-hygiene.js +40 -0
  23. package/dist/browser-evidence-hygiene.js.map +1 -0
  24. package/dist/claude-agent-sdk.d.ts +94 -0
  25. package/dist/claude-agent-sdk.js +356 -0
  26. package/dist/claude-agent-sdk.js.map +1 -0
  27. package/dist/cli.d.ts +2 -0
  28. package/dist/cli.js +5 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/codex-app-server-ui.d.ts +39 -0
  31. package/dist/codex-app-server-ui.js +327 -0
  32. package/dist/codex-app-server-ui.js.map +1 -0
  33. package/dist/codex-app-server.d.ts +141 -0
  34. package/dist/codex-app-server.js +747 -0
  35. package/dist/codex-app-server.js.map +1 -0
  36. package/dist/command-failure.d.ts +29 -0
  37. package/dist/command-failure.js +54 -0
  38. package/dist/command-failure.js.map +1 -0
  39. package/dist/computer-use-actor.d.ts +52 -0
  40. package/dist/computer-use-actor.js +48 -0
  41. package/dist/computer-use-actor.js.map +1 -0
  42. package/dist/computer-use.d.ts +232 -0
  43. package/dist/computer-use.js +615 -0
  44. package/dist/computer-use.js.map +1 -0
  45. package/dist/concurrency.d.ts +1 -0
  46. package/dist/concurrency.js +27 -0
  47. package/dist/concurrency.js.map +1 -0
  48. package/dist/concurrent-shared-world-lab.d.ts +115 -0
  49. package/dist/concurrent-shared-world-lab.js +1092 -0
  50. package/dist/concurrent-shared-world-lab.js.map +1 -0
  51. package/dist/core/git-state.d.ts +31 -0
  52. package/dist/core/git-state.js +142 -0
  53. package/dist/core/git-state.js.map +1 -0
  54. package/dist/core/index.d.ts +4 -0
  55. package/dist/core/index.js +3 -0
  56. package/dist/core/index.js.map +1 -0
  57. package/dist/core/run-primitives.d.ts +66 -0
  58. package/dist/core/run-primitives.js +120 -0
  59. package/dist/core/run-primitives.js.map +1 -0
  60. package/dist/cua-actor-lab.d.ts +620 -0
  61. package/dist/cua-actor-lab.js +2834 -0
  62. package/dist/cua-actor-lab.js.map +1 -0
  63. package/dist/device-presets.d.ts +67 -0
  64. package/dist/device-presets.js +50 -0
  65. package/dist/device-presets.js.map +1 -0
  66. package/dist/e2b-desktop-executor.d.ts +101 -0
  67. package/dist/e2b-desktop-executor.js +309 -0
  68. package/dist/e2b-desktop-executor.js.map +1 -0
  69. package/dist/e2b-desktop-launch.d.ts +144 -0
  70. package/dist/e2b-desktop-launch.js +59 -0
  71. package/dist/e2b-desktop-launch.js.map +1 -0
  72. package/dist/e2b-detached.d.ts +53 -0
  73. package/dist/e2b-detached.js +130 -0
  74. package/dist/e2b-detached.js.map +1 -0
  75. package/dist/e2b-terminal-lab.d.ts +345 -0
  76. package/dist/e2b-terminal-lab.js +1467 -0
  77. package/dist/e2b-terminal-lab.js.map +1 -0
  78. package/dist/env-file.d.ts +14 -0
  79. package/dist/env-file.js +108 -0
  80. package/dist/env-file.js.map +1 -0
  81. package/dist/feedback.d.ts +51 -0
  82. package/dist/feedback.js +313 -0
  83. package/dist/feedback.js.map +1 -0
  84. package/dist/image-evidence.d.ts +2 -0
  85. package/dist/image-evidence.js +33 -0
  86. package/dist/image-evidence.js.map +1 -0
  87. package/dist/index.d.ts +63 -0
  88. package/dist/index.js +33 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/init-templates.d.ts +12 -0
  91. package/dist/init-templates.js +369 -0
  92. package/dist/init-templates.js.map +1 -0
  93. package/dist/init.d.ts +26 -0
  94. package/dist/init.js +343 -0
  95. package/dist/init.js.map +1 -0
  96. package/dist/lab-app-runner.d.ts +78 -0
  97. package/dist/lab-app-runner.js +403 -0
  98. package/dist/lab-app-runner.js.map +1 -0
  99. package/dist/lab-config.d.ts +578 -0
  100. package/dist/lab-config.js +1751 -0
  101. package/dist/lab-config.js.map +1 -0
  102. package/dist/lab-engine.d.ts +77 -0
  103. package/dist/lab-engine.js +216 -0
  104. package/dist/lab-engine.js.map +1 -0
  105. package/dist/lab-preflight.d.ts +67 -0
  106. package/dist/lab-preflight.js +385 -0
  107. package/dist/lab-preflight.js.map +1 -0
  108. package/dist/labs.d.ts +53 -0
  109. package/dist/labs.js +176 -0
  110. package/dist/labs.js.map +1 -0
  111. package/dist/observer-assets.d.ts +2 -0
  112. package/dist/observer-assets.js +2630 -0
  113. package/dist/observer-assets.js.map +1 -0
  114. package/dist/observer-data.d.ts +63 -0
  115. package/dist/observer-data.js +145 -0
  116. package/dist/observer-data.js.map +1 -0
  117. package/dist/observer-static.d.ts +39 -0
  118. package/dist/observer-static.js +192 -0
  119. package/dist/observer-static.js.map +1 -0
  120. package/dist/observer.d.ts +46 -0
  121. package/dist/observer.js +353 -0
  122. package/dist/observer.js.map +1 -0
  123. package/dist/openai-responses-cu.d.ts +113 -0
  124. package/dist/openai-responses-cu.js +531 -0
  125. package/dist/openai-responses-cu.js.map +1 -0
  126. package/dist/oss-lab.d.ts +52 -0
  127. package/dist/oss-lab.js +299 -0
  128. package/dist/oss-lab.js.map +1 -0
  129. package/dist/oss-meta-lab-scoring.d.ts +15 -0
  130. package/dist/oss-meta-lab-scoring.js +145 -0
  131. package/dist/oss-meta-lab-scoring.js.map +1 -0
  132. package/dist/oss-meta-lab.d.ts +279 -0
  133. package/dist/oss-meta-lab.js +4889 -0
  134. package/dist/oss-meta-lab.js.map +1 -0
  135. package/dist/oss-remote-telemetry.d.ts +77 -0
  136. package/dist/oss-remote-telemetry.js +403 -0
  137. package/dist/oss-remote-telemetry.js.map +1 -0
  138. package/dist/persona.d.ts +35 -0
  139. package/dist/persona.js +133 -0
  140. package/dist/persona.js.map +1 -0
  141. package/dist/pi-agent-core.d.ts +77 -0
  142. package/dist/pi-agent-core.js +203 -0
  143. package/dist/pi-agent-core.js.map +1 -0
  144. package/dist/program.d.ts +54 -0
  145. package/dist/program.js +2347 -0
  146. package/dist/program.js.map +1 -0
  147. package/dist/redaction.d.ts +90 -0
  148. package/dist/redaction.js +292 -0
  149. package/dist/redaction.js.map +1 -0
  150. package/dist/run.d.ts +784 -0
  151. package/dist/run.js +4555 -0
  152. package/dist/run.js.map +1 -0
  153. package/dist/scripted-browser-actor.d.ts +294 -0
  154. package/dist/scripted-browser-actor.js +1286 -0
  155. package/dist/scripted-browser-actor.js.map +1 -0
  156. package/dist/scripted-browser-lab.d.ts +107 -0
  157. package/dist/scripted-browser-lab.js +738 -0
  158. package/dist/scripted-browser-lab.js.map +1 -0
  159. package/dist/shared-world-lab.d.ts +208 -0
  160. package/dist/shared-world-lab.js +1048 -0
  161. package/dist/shared-world-lab.js.map +1 -0
  162. package/dist/source-archive.d.ts +82 -0
  163. package/dist/source-archive.js +365 -0
  164. package/dist/source-archive.js.map +1 -0
  165. package/dist/stop-conditions.d.ts +26 -0
  166. package/dist/stop-conditions.js +66 -0
  167. package/dist/stop-conditions.js.map +1 -0
  168. package/dist/terminal-agent-actor.d.ts +36 -0
  169. package/dist/terminal-agent-actor.js +23 -0
  170. package/dist/terminal-agent-actor.js.map +1 -0
  171. package/docs/architecture/actor-contract.md +431 -0
  172. package/docs/architecture/github-feedback-loop.md +189 -0
  173. package/docs/architecture/local-codex-tui-actor.md +213 -0
  174. package/docs/architecture/observer.md +118 -0
  175. package/docs/architecture/oss-lab-poc.md +242 -0
  176. package/docs/architecture/project-layout.md +166 -0
  177. package/docs/architecture/state-driven-executor.md +203 -0
  178. package/docs/architecture/terminal-product-lane.md +148 -0
  179. package/docs/contracts/adapter-fixtures.md +80 -0
  180. package/docs/contracts/core.md +71 -0
  181. package/docs/contracts/feedback.md +145 -0
  182. package/docs/contracts/policy.md +305 -0
  183. package/docs/contracts/run-bundle.md +358 -0
  184. package/docs/contracts/schemas.md +984 -0
  185. package/docs/goals/current.md +409 -0
  186. package/docs/principles/invariants-and-defaults.md +135 -0
  187. package/docs/principles/self-driving-harness.md +129 -0
  188. package/docs/product/open-source-install-experience.md +229 -0
  189. package/docs/ramp/README.md +200 -0
  190. package/docs/release/open-source-readiness.md +208 -0
  191. package/docs/release/public-readiness-standard.md +205 -0
  192. package/docs/roadmap/world-class-open-source-v0.md +311 -0
  193. package/package.json +102 -8
  194. package/skills/humanish/SKILL.md +244 -0
  195. package/skills/humanish/agents/openai.yaml +7 -0
  196. package/index.js +0 -1
@@ -0,0 +1,620 @@
1
+ import type { ActorCompletionReason, ActorPersonaRef, ActorStatus } from "./actor-contract.js";
2
+ import { type BrowserLabAdapterHooks } from "./adapter-extension.js";
3
+ import { type CuaActorDescriptor } from "./actor-registry.js";
4
+ import type { CuaActorSessionOptions } from "./computer-use-actor.js";
5
+ import type { CuaExecutor, CuaLoopResult, CuaProvider } from "./computer-use.js";
6
+ import { type E2BDesktopModule, type E2BDesktopSandbox } from "./e2b-desktop-launch.js";
7
+ import { type DetachedTimers } from "./e2b-detached.js";
8
+ import { type DevicePreset } from "./device-presets.js";
9
+ import { type LabActorLane, type LabConfig, type LabDesktopBrowser, type LabSubjectServe, type LabSubjectState } from "./lab-config.js";
10
+ import { renderObserver, type ObserverResult } from "./observer.js";
11
+ import { type LocalTreeArchive } from "./source-archive.js";
12
+ import type { StopWhen } from "./stop-conditions.js";
13
+ import { type RunBundle, type RunRerunLineage, type RunProviderResource, type RunSubjectProvenance, type RunSubjectStateStepRecord } from "./run.js";
14
+ export declare const CUA_ACTOR_LAB_SCHEMA = "humanish.cua-lab-result.v2";
15
+ export declare const CUA_FANOUT_STRATEGY: "per-lane-worlds";
16
+ export declare const CUA_ACTOR_LAB_PROVIDER_METADATA: {
17
+ readonly mode: "cua-actor-lab";
18
+ readonly tool: "humanish";
19
+ };
20
+ export interface DesktopBrowserEvidence {
21
+ requested: LabDesktopBrowser;
22
+ resolved?: string;
23
+ }
24
+ export declare const SUBJECT_DIR = "/home/user/subject";
25
+ /**
26
+ * One phase-boundary event from the shared subject provisioning pipeline (clone or local-tree
27
+ * route): started/completed pairs at each named boundary, never per poll tick (the detached
28
+ * primitive in e2b-detached.ts already polls every 1.5-3s internally; only the boundary itself
29
+ * is surfaced here). Message text is public-safe by construction: no URLs beyond the existing
30
+ * publicAppUrl convention, no paths, no command text. Completed events carry `ok` and
31
+ * `durationMs`; started events (and the fire-and-forget `subject.serve.started`) carry neither.
32
+ */
33
+ export interface SubjectPhaseEvent {
34
+ at: string;
35
+ type: string;
36
+ ok?: boolean;
37
+ durationMs?: number;
38
+ message: string;
39
+ }
40
+ /**
41
+ * Library-level hooks. `prepareDesktop` runs after sandbox creation and before subject
42
+ * provisioning / browser launch — library callers use it for extra in-sandbox setup beyond
43
+ * what `subject.serve` declares (or to provision an app-url subject entirely). The rest are
44
+ * DI seams so CI drives the full path with fakes at zero network/zero spend.
45
+ */
46
+ export interface CuaActorLabHooks extends BrowserLabAdapterHooks {
47
+ /**
48
+ * Runs after sandbox creation and before subject provisioning / browser launch. Widened
49
+ * back-compatibly with per-lane context so a library caller can provision the right app-url
50
+ * subject per lane (a one-arg `(desktop) => …` still satisfies the type). Called once per lane.
51
+ */
52
+ prepareDesktop?: (desktop: E2BDesktopSandbox, lane: {
53
+ laneId: string;
54
+ laneIndex: number;
55
+ laneCount: number;
56
+ }) => Promise<void>;
57
+ /**
58
+ * Pre-flight hook: receives the resolved lane plan BEFORE any sandbox or provider call (dry-run
59
+ * AND live). The engine also prints the plan to stderr; this seam lets tests assert it without
60
+ * scraping stderr. Identical plan in dry-run, marked $0.
61
+ */
62
+ onPreflight?: (plan: CuaLanePlan) => void;
63
+ /**
64
+ * Live subject-provisioning phase sink: one call per started/completed boundary (clone,
65
+ * upload/extract, install, build, serve start, ready, and each subject.state seed-step
66
+ * group). Defaults to one stderr line per event, prefixed with the lane id when laneCount > 1
67
+ * (single-lane emission is unconditional: single-lane silence for the whole boot is the bug
68
+ * this event stream closes). Override in tests to capture instead of writing to real stderr.
69
+ */
70
+ onPhase?: (event: SubjectPhaseEvent, ctx: {
71
+ laneId: string;
72
+ laneCount: number;
73
+ }) => void;
74
+ /**
75
+ * Runtime-only live desktop stream callback. The URL carries an auth key and must never be
76
+ * persisted into run artifacts; callers use it to hydrate an attached Observer server.
77
+ */
78
+ onRuntimeStreamReady?: (stream: {
79
+ laneId: string;
80
+ sandboxId: string;
81
+ simId: string;
82
+ streamId: string;
83
+ url: string;
84
+ }) => Promise<void> | void;
85
+ loadDesktopModule?: () => Promise<E2BDesktopModule>;
86
+ runSession?: (options: CuaActorSessionOptions) => Promise<CuaLoopResult>;
87
+ /**
88
+ * Supply a custom executor (e.g. a window.* JS-contract bridge over an already-running local
89
+ * dev server). When present (with `buildProvider`), `runCuaActorLab` takes the IN-PROCESS
90
+ * branch: it NEVER loads the E2B module, creates a sandbox, runs prepareDesktop, provisions a
91
+ * clone, opens a browser, or starts a stream — so `result.sandbox` is omitted, the verifiable
92
+ * "no E2B SDK call" proof. The whole bundle/Observer/redaction composition below the session
93
+ * call is desktop-agnostic and runs unchanged. Receives the resolved config, the
94
+ * registry-resolved descriptor, and the entry appUrl.
95
+ */
96
+ buildExecutor?: (ctx: {
97
+ config: LabConfig;
98
+ actor: CuaActorDescriptor;
99
+ appUrl: string;
100
+ }) => Promise<CuaExecutor>;
101
+ /**
102
+ * Supply a custom provider (a "brain" reasoning over app STATE). REQUIRED alongside
103
+ * `buildExecutor` — the default OpenAI provider is vision-based (requiresFrame) and would fail
104
+ * closed against a state-only executor that returns no screenshot. (`buildProvider` ALONE is
105
+ * allowed — that is just a model swap on the normal E2B route.)
106
+ */
107
+ buildProvider?: (ctx: {
108
+ config: LabConfig;
109
+ actor: CuaActorDescriptor;
110
+ }) => Promise<CuaProvider>;
111
+ env?: Record<string, string | undefined>;
112
+ renderObserverFn?: typeof renderObserver;
113
+ /** Injected clock/sleep for the detached-step polling (tests only). */
114
+ detachedTimers?: DetachedTimers;
115
+ /**
116
+ * Local-tree packing DI seam (tests only, no npm dependency needed to exercise the route):
117
+ * defaults to createLocalTreeArchive(root, opts) plus a host-side read of the produced
118
+ * archive file into an ArrayBuffer. Called ONCE per run, before lane fan-out, on the live
119
+ * local-tree route; the result (archive metadata + bytes) is shared byte-identically across
120
+ * every fan-out lane, so one archiveSha256 describes every lane's packed content.
121
+ */
122
+ packLocalTree?: (args: {
123
+ root: string;
124
+ extraExclude?: string[];
125
+ maxArchiveBytes?: number;
126
+ }) => Promise<{
127
+ archive: LocalTreeArchive;
128
+ buffer: ArrayBuffer;
129
+ }>;
130
+ }
131
+ export interface RunCuaActorLabOptions {
132
+ cwd: string;
133
+ config: LabConfig;
134
+ /** Resolved upstream (scenario.mode + CLI override); defaults safe (dry-run). */
135
+ dryRun: boolean;
136
+ open?: boolean;
137
+ runId?: string;
138
+ /** CLI `--count` override for the homogeneous fan-out lane count (ignored when a `lanes`
139
+ * roster is declared — a roster's length is authoritative). */
140
+ countOverride?: number;
141
+ /** Explicitly create a new run containing failed or selected lanes from a prior fan-out run. */
142
+ rerun?: {
143
+ sourceRunId: string;
144
+ laneIds?: string[];
145
+ };
146
+ hooks?: CuaActorLabHooks;
147
+ onObserverReady?: (observer: ObserverResult & {
148
+ ok: true;
149
+ }) => Promise<void> | void;
150
+ }
151
+ /** A lane's row in the pre-flight plan: identity + the device/persona it will drive. The prompt
152
+ * text never leaks — only a sha256-16 digest of the composed instructions. */
153
+ export interface CuaLanePlanEntry {
154
+ id: string;
155
+ actorType?: string;
156
+ surface?: string;
157
+ caseGroup?: string;
158
+ /** 1-based display index. */
159
+ index: number;
160
+ persona: string;
161
+ device: string;
162
+ resolution: [number, number];
163
+ instructionDigest: string;
164
+ /** Present only when a lane overrides subject.appUrl; digest avoids leaking preview hosts in plan logs. */
165
+ targetDigest?: string;
166
+ }
167
+ /** The pre-flight spend/lane plan (pure; printed to stderr + recorded as a bundle event before
168
+ * any sandbox or provider call; identical in dry-run, marked $0). */
169
+ export interface CuaLanePlan {
170
+ strategy: typeof CUA_FANOUT_STRATEGY;
171
+ laneCount: number;
172
+ /** Effective in-flight bound (config default min(N,3), only LOWERED by the env override). */
173
+ concurrency: number;
174
+ /** ceil(laneCount / concurrency). */
175
+ waves: number;
176
+ /** Per-lane session wall-clock budget (execution.timeoutMs); there is no run-level wall clock. */
177
+ perLaneSessionBudgetMs: number;
178
+ /** Worst-case TOTAL sandbox-minutes across all lanes (each lane's full sandbox deadline). */
179
+ worstCaseSandboxMinutes: number;
180
+ /** True for a dry-run plan (no spend); the same table appears live. */
181
+ dryRun: boolean;
182
+ lanes: CuaLanePlanEntry[];
183
+ }
184
+ /** One lane's outcome in the result projection. ALWAYS present in `result.lanes` (length 1 at
185
+ * N=1). A `blocked` lane is one the pipeline-gate / fail-fast skipped before it ran. */
186
+ export interface CuaLaneResult {
187
+ id: string;
188
+ actorType?: string;
189
+ surface?: string;
190
+ caseGroup?: string;
191
+ index: number;
192
+ persona: string;
193
+ device: string;
194
+ resolution: [number, number];
195
+ /** Terminal lane status; "blocked" = skipped (gate/fail-fast); "contract_proof_only" = dry-run. */
196
+ status: ActorStatus | "blocked" | "contract_proof_only";
197
+ ok: boolean;
198
+ session?: {
199
+ status: ActorStatus;
200
+ completionReason: ActorCompletionReason;
201
+ reason: string;
202
+ screenshots: number;
203
+ };
204
+ sandbox?: {
205
+ sandboxId: string;
206
+ killed: boolean;
207
+ streamUrlPresent: boolean;
208
+ };
209
+ subject: CuaSubjectProjection;
210
+ /** Set when the lane was skipped (pinned reason string). */
211
+ skippedReason?: string;
212
+ error?: {
213
+ code: CuaActorLabErrorCode;
214
+ message: string;
215
+ };
216
+ }
217
+ /** Aggregate counts across lanes. */
218
+ export interface CuaLaneSummary {
219
+ strategy: typeof CUA_FANOUT_STRATEGY;
220
+ total: number;
221
+ /** Lanes whose own verdict is ok (terminal, engaged, no harness error). */
222
+ passed: number;
223
+ /** Lanes skipped by the pipeline gate / fail-fast. */
224
+ skipped: number;
225
+ /** Lanes that ended in a harness error. */
226
+ harnessErrors: number;
227
+ /** Lanes that returned goal_satisfied with zero engagement (hollow). */
228
+ hollow: number;
229
+ concurrency: number;
230
+ waves: number;
231
+ }
232
+ export type CuaActorLabErrorCode = "HUMANISH_CUA_LAB_FAILED" | "HUMANISH_CUA_LAB_KEYS_MISSING" | "HUMANISH_CUA_LAB_SUBJECT_ENV_MISSING" | "HUMANISH_CUA_LAB_ACTOR_UNSUPPORTED" | "HUMANISH_CUA_LAB_SUBJECT_INVALID" | "HUMANISH_CUA_LAB_SUBJECT_UNSAFE" | "HUMANISH_CUA_LAB_EXECUTOR_NO_PROVIDER" | "HUMANISH_CUA_LAB_LOCAL_APP_NO_EXECUTOR" | "HUMANISH_CUA_LAB_FANOUT_INVALID" | "HUMANISH_CUA_LAB_RERUN_INVALID" | "HUMANISH_CUA_LAB_DEVICE_GEOMETRY";
233
+ /** Subject provenance projection (invariant 5): what the actor actually drove. */
234
+ export interface CuaSubjectProjection {
235
+ source: "app-url" | "clone" | "local-tree";
236
+ /** Clone-route only: the (possibly redacted) owner/repo slug. */
237
+ repo?: string;
238
+ /** Cloned commit SHA (clone route) or host-side HEAD at pack time (local-tree route, when
239
+ * the packed root was a git work tree). */
240
+ commit?: string;
241
+ /** Local-tree-route only: 64-hex sha256 over the sorted packed-entries list: the content
242
+ * pin for a tree that cannot be commit-pinned. Absent on dry-run (nothing was packed). */
243
+ archiveSha256?: string;
244
+ /** Local-tree-route only: host-side porcelain status at pack time (true when the working
245
+ * tree had uncommitted changes). Absent when the packed root was not a git work tree. */
246
+ dirty?: boolean;
247
+ /** Declared env NAMES provisioned for the subject (values never surface anywhere). */
248
+ envNames?: string[];
249
+ /** The subject's state story (seeded digests / UNPINNED external / declared-not-run /
250
+ * undeclared): the same block the run bundle records. */
251
+ state: RunSubjectProvenance["state"];
252
+ }
253
+ /** The provisioned-route-only shape threaded through as buildCuaBundle's subjectProvenance arg
254
+ * (clone or local-tree; an app-url subject stays undeclared, which buildCuaBundle's own
255
+ * default branch already handles without this type). */
256
+ export type CuaSubjectProvenanceArg = {
257
+ source: "clone";
258
+ repo: string;
259
+ commit?: string;
260
+ envNames: string[];
261
+ state: RunSubjectProvenance["state"];
262
+ } | {
263
+ source: "local-tree";
264
+ archiveSha256?: string;
265
+ commit?: string;
266
+ dirty?: boolean;
267
+ envNames: string[];
268
+ state: RunSubjectProvenance["state"];
269
+ };
270
+ export interface CuaActorLabResult {
271
+ schema: typeof CUA_ACTOR_LAB_SCHEMA;
272
+ /** True when the bundle verified AND (dry-run, or the session reached a terminal verdict
273
+ * without a harness error). The actor's pass/fail is evidence, not the lab's exit code. */
274
+ ok: boolean;
275
+ cwd: string;
276
+ labId: string;
277
+ /** The registry-resolved actor id that ran (or would run) the session. */
278
+ actor: string;
279
+ appUrl: string;
280
+ dryRun: boolean;
281
+ runId: string;
282
+ session?: {
283
+ status: ActorStatus;
284
+ completionReason: ActorCompletionReason;
285
+ reason: string;
286
+ screenshots: number;
287
+ };
288
+ sandbox?: {
289
+ sandboxId: string;
290
+ killed: boolean;
291
+ /** The stream URL itself (carries an auth key) is runtime-only and is deliberately NOT
292
+ * surfaced on the result — the sandbox is already dead by the time the result exists. */
293
+ streamUrlPresent: boolean;
294
+ };
295
+ /** Subject provenance (invariant 5): what the actor actually drove. At N>1 this is the
296
+ * unanimity-gated aggregate (top-level `commit` only when every lane resolved the same one). */
297
+ subject?: CuaSubjectProjection;
298
+ /** The pre-flight lane plan (present once lanes resolve; absent on early validation errors). */
299
+ plan?: CuaLanePlan;
300
+ /** Per-lane results — ALWAYS present once lanes resolve (length 1 at N=1). */
301
+ lanes?: CuaLaneResult[];
302
+ /** Aggregate lane counts. */
303
+ laneSummary?: CuaLaneSummary;
304
+ /** Present when this run explicitly re-executes selected lanes from a prior CUA fan-out run. */
305
+ rerun?: RunRerunLineage;
306
+ observer?: ObserverResult;
307
+ warnings: string[];
308
+ error?: {
309
+ code: CuaActorLabErrorCode;
310
+ message: string;
311
+ };
312
+ }
313
+ /** A fully-resolved fan-out lane: identity, the composed prompt, and the device geometry it
314
+ * renders at. Internal — the public projection is CuaLanePlanEntry / CuaLaneResult. */
315
+ export interface CuaLaneSpec {
316
+ laneId: string;
317
+ actorType?: string;
318
+ surface?: string;
319
+ caseGroup?: string;
320
+ /** 0-based. */
321
+ laneIndex: number;
322
+ simId: string;
323
+ streamId: string;
324
+ persona: ActorPersonaRef;
325
+ instructions: string;
326
+ /** App-url fan-out only: this lane's explicit browser target; absent falls back to deps.appUrl. */
327
+ targetUrl?: string;
328
+ /** Deterministic harness-owned completion guard. Lane-level override, else actor default. */
329
+ stopWhen?: StopWhen;
330
+ deviceName: string;
331
+ devicePreset: DevicePreset;
332
+ resolution: [number, number];
333
+ /** "" for N=1 (screenshots/<name>); the laneId for N>1 (screenshots/<laneId>/<name>). */
334
+ screenshotDir: string;
335
+ /** "actor.json" for N=1; "actors/<streamId>.json" for N>1. */
336
+ traceArtifactPath: string;
337
+ }
338
+ /** Compose one lane's actor prompt: persona line + device line + mission + per-lane steer.
339
+ * At N=1 (homogeneous, no roster) this reproduces the prior composeInstructions byte-for-byte. */
340
+ export declare function composeLaneInstructions(args: {
341
+ mission: string;
342
+ persona?: string;
343
+ instruction?: string;
344
+ device: {
345
+ name: string;
346
+ preset: DevicePreset;
347
+ };
348
+ }): {
349
+ instructions: string;
350
+ persona: ActorPersonaRef;
351
+ };
352
+ /**
353
+ * Resolve a lane's device + rendered resolution (most-specific wins, exactly as the single-lane
354
+ * path always has): a raw execution.desktop.resolution escape hatch (only legal when no lane
355
+ * sets a device — XOR enforced at parse) → the lane's named device → the run-wide
356
+ * execution.desktop.device → the default preset. A raw resolution is an unnamed custom desktop
357
+ * (non-mobile, DSF 1): we never claim a named preset's mobile/DPR for hand-set geometry.
358
+ */
359
+ export declare function resolveLaneDevice(config: LabConfig, lane: LabActorLane | undefined): {
360
+ name: string;
361
+ preset: DevicePreset;
362
+ resolution: [number, number];
363
+ };
364
+ /**
365
+ * Pure pre-flight plan resolver (runs in dry-run AND live). Returns the lane table, the
366
+ * effective concurrency, the wave count, the per-lane session budget, and the worst-case total
367
+ * sandbox-minutes — BEFORE any sandbox or provider call. The same plan appears in dry-run,
368
+ * marked $0 (dryRun: true).
369
+ */
370
+ export declare function resolveCuaLanePlan(config: LabConfig, opts?: {
371
+ countOverride?: number;
372
+ env?: Record<string, string | undefined>;
373
+ dryRun?: boolean;
374
+ }): CuaLanePlan;
375
+ /** Shared deps every lane runner needs (resolved once in the engine). */
376
+ export interface CuaLaneDeps {
377
+ config: LabConfig;
378
+ descriptor: CuaActorDescriptor;
379
+ appUrl: string;
380
+ cloneRoute: boolean;
381
+ /** Optional so out-of-scope callers building CuaLaneDeps directly (other engines reusing
382
+ * runCuaLane) do not need to know about the local-tree route; undefined behaves as false. */
383
+ localTreeRoute?: boolean;
384
+ serve?: LabSubjectServe;
385
+ subjectRepo?: string;
386
+ subjectEnvNames: string[];
387
+ hasGithubToken: boolean;
388
+ /** Local-tree route only: the once-per-run packed archive bytes, shared byte-identically
389
+ * across every fan-out lane's upload step. Absent on dry-run and every other route. */
390
+ localTreeArchiveBuffer?: ArrayBuffer;
391
+ env: Record<string, string | undefined>;
392
+ openaiApiKey: string;
393
+ e2bApiKey: string;
394
+ requestTimeoutMs: number;
395
+ perLaneSandboxMs: number;
396
+ timeoutMs: number;
397
+ laneCount: number;
398
+ artifactRoot: string;
399
+ redactScreenshots: boolean;
400
+ scrubKnownValues: (text: string) => string;
401
+ runSession: (options: CuaActorSessionOptions) => Promise<CuaLoopResult>;
402
+ hooks: CuaActorLabHooks;
403
+ /** Lane-0 only: signal the pipeline gate after provisioning succeeds (true) or fails (false). */
404
+ signalProvisioned?: (ok: boolean) => void;
405
+ }
406
+ /** One lane's end-to-end run outcome (internal; projected into CuaLaneResult + the bundle). */
407
+ export interface LaneRunOutcome {
408
+ spec: CuaLaneSpec;
409
+ session?: CuaLoopResult;
410
+ sessionError?: string;
411
+ sandboxId?: string;
412
+ killed: boolean;
413
+ streamUrlPresent: boolean;
414
+ screenshots: string[];
415
+ subjectCommit?: string;
416
+ desktopBrowser?: DesktopBrowserEvidence;
417
+ stateStepRecords: RunSubjectStateStepRecord[];
418
+ /** Completed subject-phase records (clone/upload/extract/install/build/ready/state groups),
419
+ * folded into bundle.events at build time. Empty on the in-process route (no provisioning). */
420
+ phaseRecords: SubjectPhaseEvent[];
421
+ warnings: string[];
422
+ /** Set when the lane was skipped by the pipeline gate / fail-fast (a pinned reason). */
423
+ skippedReason?: string;
424
+ noEngagement: boolean;
425
+ selfReportedBlocker: boolean;
426
+ harnessError: boolean;
427
+ failureCode?: CuaActorLabErrorCode;
428
+ entryKind?: "local-app";
429
+ }
430
+ /** Build a lane's writeScreenshot closure: writes under screenshots/<screenshotDir>/ and records
431
+ * the relative path the trace references (screenshots/<name> at N=1; screenshots/<laneId>/<name>
432
+ * at N>1). */
433
+ export declare function makeLaneWriteScreenshot(artifactRoot: string, spec: {
434
+ screenshotDir: string;
435
+ }, screenshots: string[]): (name: string, bytes: Buffer) => Promise<string>;
436
+ /**
437
+ * Build the xdotool command that makes a browser window fill the desktop.
438
+ * Exported (pure) for contract tests. A window manager can ignore Chrome's
439
+ * --window-size, so xdotool is the robust path: move the window to the origin,
440
+ * then size it to the exact desktop resolution so Observer screenshots carry no
441
+ * dead margin around the browser.
442
+ */
443
+ export declare function buildFillDesktopWindowCommand(windowId: string, width: number, height: number): string;
444
+ export declare function makeChromeBrowserStateObserver(desktop: E2BDesktopSandbox, requestTimeoutMs: number): () => Promise<{
445
+ url?: string;
446
+ title?: string;
447
+ text?: string;
448
+ }>;
449
+ /**
450
+ * Run ONE E2B desktop lane end-to-end: create the sandbox (per-lane metadata + the lane's device
451
+ * resolution), prepareDesktop, verify geometry, (clone+serve+seed the subject per lane), open the
452
+ * browser, run the session, and ALWAYS tear down THIS lane's sandbox BY ID in a finally. Never
453
+ * enumerates sandboxes. Extracted from the former single-lane block; at N=1 it writes the exact
454
+ * same artifacts (actor.json, screenshots/<name>) the bundle has always referenced.
455
+ */
456
+ export declare function runCuaLane(spec: CuaLaneSpec, deps: CuaLaneDeps): Promise<LaneRunOutcome>;
457
+ export declare function runCuaActorLab(options: RunCuaActorLabOptions): Promise<CuaActorLabResult>;
458
+ /**
459
+ * Provision a clone subject inside the sandbox: clone → the shared serve pipeline
460
+ * (install → state(before-build) → build → state(before-start) → start → readiness
461
+ * probe → state(after-ready)). Returns the latest subject HEAD after successful
462
+ * provisioning. Throws (with a capped log tail for the caller to redact) on any failing step:
463
+ * the lab persists that as a failed-evidence bundle.
464
+ *
465
+ * Auth: when GITHUB_TOKEN is among the declared subject env names, the clone authenticates
466
+ * via an Authorization header computed IN-SANDBOX from the provisioned env: the token never
467
+ * appears in the script text, the process argv beyond the transient git call, the clone URL,
468
+ * or .git/config.
469
+ */
470
+ export declare function provisionCloneSubject(desktop: E2BDesktopSandbox, args: {
471
+ repo: string;
472
+ depth: number;
473
+ serve: LabSubjectServe;
474
+ /** Declared subject state (seed steps; external declaration is provenance-only). */
475
+ state?: LabSubjectState;
476
+ hasGithubToken: boolean;
477
+ requestTimeoutMs: number;
478
+ /** Literal scrubber for known provisioned values, applied to log tails PRE-truncation. */
479
+ scrub: (text: string) => string;
480
+ /** Called the moment the cloned commit resolves, so provenance survives later failures. */
481
+ onCommit?: (commit: string) => void;
482
+ /** Called the moment each state step finishes (mirrors onCommit), success or failure. */
483
+ onStateStep?: (record: RunSubjectStateStepRecord) => void;
484
+ /** Called at each phase boundary (started/completed): clone, install, build, serve start,
485
+ * ready, and each subject.state seed-step group. */
486
+ onPhase?: (event: SubjectPhaseEvent) => void;
487
+ } & DetachedTimers): Promise<string | undefined>;
488
+ /**
489
+ * Provision a local-tree subject inside the sandbox: upload the once-per-run packed archive
490
+ * (identical bytes across every fan-out lane) → extract it into SUBJECT_DIR → the
491
+ * same shared serve pipeline provisionCloneSubject uses. Unlike the clone route there is no
492
+ * in-sandbox git refresh: the archive excludes .git entirely (see source-archive.ts), so
493
+ * subject identity is the host-side LocalTreeArchive captured at pack time, never anything
494
+ * resolved in-sandbox.
495
+ */
496
+ export declare function provisionLocalTreeSubject(desktop: E2BDesktopSandbox, args: {
497
+ /** The once-per-run packed archive bytes (shared byte-identically across every lane). */
498
+ archiveBuffer: ArrayBuffer;
499
+ serve: LabSubjectServe;
500
+ /** Declared subject state (seed steps; external declaration is provenance-only). */
501
+ state?: LabSubjectState;
502
+ requestTimeoutMs: number;
503
+ /** Literal scrubber for known provisioned values, applied to log tails PRE-truncation. */
504
+ scrub: (text: string) => string;
505
+ /** Called the moment each state step finishes, success or failure. */
506
+ onStateStep?: (record: RunSubjectStateStepRecord) => void;
507
+ /** Called at each phase boundary (started/completed): upload, extract, install, build,
508
+ * serve start, ready, and each subject.state seed-step group. */
509
+ onPhase?: (event: SubjectPhaseEvent) => void;
510
+ } & DetachedTimers): Promise<void>;
511
+ /**
512
+ * Default local-tree packing implementation: createLocalTreeArchive(root, opts) on the host,
513
+ * then a single read of the produced archive file into an ArrayBuffer for upload. The DI seam
514
+ * (CuaActorLabHooks.packLocalTree) overrides this in deterministic tests so they never require
515
+ * tar/git.
516
+ */
517
+ export declare function defaultPackLocalTree(args: {
518
+ root: string;
519
+ extraExclude?: string[];
520
+ maxArchiveBytes?: number;
521
+ }): Promise<{
522
+ archive: LocalTreeArchive;
523
+ buffer: ArrayBuffer;
524
+ }>;
525
+ /** sha256 hex of the exact command string, first 16 chars (the promptDigest convention). */
526
+ export declare function commandDigestOf(command: string): string;
527
+ /**
528
+ * Resolve the bundle's state marker from the declaration and what actually ran.
529
+ * Precedence: external declared → "unpinned" (seed records, if any, stay attached — a
530
+ * migrated external DB is still unpinned overall); else seed declared → "seeded" only when
531
+ * every declared step executed ok on a live run, otherwise "declared-not-run" (dry-run
532
+ * contract bundles and failed live provisioning); no declaration → "undeclared".
533
+ */
534
+ export declare function resolveSubjectState(args: {
535
+ declared: LabSubjectState | undefined;
536
+ dryRun: boolean;
537
+ executed: RunSubjectStateStepRecord[];
538
+ }): RunSubjectProvenance["state"];
539
+ /**
540
+ * Project a computer-use session into a humanish.run-bundle.v1. The load-bearing line is
541
+ * `stream.actor = session.trace` — the provider-neutral ActorTrace seam the Observer renders.
542
+ * Exported for the bundle-builder tests.
543
+ */
544
+ export declare function buildCuaBundle(args: {
545
+ actorId: string;
546
+ appUrl: string;
547
+ laneId?: string;
548
+ actorType?: string;
549
+ surface?: string;
550
+ caseGroup?: string;
551
+ createdAt: string;
552
+ dryRun: boolean;
553
+ labId: string;
554
+ labTitle?: string;
555
+ mission: string;
556
+ persona: ActorPersonaRef;
557
+ resolution: [number, number];
558
+ /** Device metadata for the stream viewport (honest; isMobile/DSF are not rendered on this route). */
559
+ deviceScaleFactor?: number;
560
+ isMobile?: boolean;
561
+ runId: string;
562
+ screenshots: string[];
563
+ /**
564
+ * Capture-time screenshot policy ("blurred" when policies.redactScreenshots, else "raw").
565
+ * When a session ran, its trace's `redaction.screenshots` is the evidence-of-record and
566
+ * wins; this fallback keeps labels honest for frames written before a mid-session failure
567
+ * (no trace exists to testify then). Defaults to "raw" — the engine default.
568
+ */
569
+ captureRedaction?: "raw" | "blurred";
570
+ session?: CuaLoopResult;
571
+ sessionError?: string;
572
+ source: RunBundle["source"];
573
+ /** Provisioned-route provenance (clone or local-tree): what the actor actually drove (names
574
+ * + digests only, never values or command text), including the subject's state story. */
575
+ subjectProvenance?: CuaSubjectProvenanceArg;
576
+ /**
577
+ * Entry kind for the non-clone subject.declared event (invariant 5 — declare what the subject
578
+ * WAS). "local-app": an already-running LOCAL dev server driven in-process, un-pinnable —
579
+ * declared honestly as caller-provisioned/unpinned with no E2B. Absent: a plain app-url entry.
580
+ */
581
+ entryKind?: "local-app";
582
+ /** The custom E2B desktop template (image) this lane launched on, when configured (provenance). */
583
+ desktopTemplate?: string;
584
+ /** The configured browser choice and the command that opened, when explicitly configured. */
585
+ desktopBrowser?: DesktopBrowserEvidence;
586
+ traceArtifactPath?: string;
587
+ providerResources?: RunProviderResource[];
588
+ inProgress?: boolean;
589
+ /** Completed subject-phase records (clone/upload/extract/install/build/ready/state groups)
590
+ * to fold into bundle.events, so run.json carries real phase timing after the fact. */
591
+ phaseEvents?: SubjectPhaseEvent[];
592
+ }): RunBundle;
593
+ /**
594
+ * Project N>1 fan-out lanes into a humanish.run-bundle.v1 (the evidence schema is unchanged; this
595
+ * is a new producer for the multi-stream shape). One sim + one stream per lane; per-lane
596
+ * provenance/session events; a recorded `cua-lab.fanout.plan` event (and a `cua-lab.fanout.fail-fast`
597
+ * event when a harness error skipped queued lanes). N-ary verify/Observer already handle multiple
598
+ * streams. The N=1 path NEVER reaches here (buildCuaBundle owns it, byte-stable).
599
+ */
600
+ export declare function buildCuaFanoutBundle(args: {
601
+ specs: CuaLaneSpec[];
602
+ outcomes?: LaneRunOutcome[];
603
+ laneSubjects: CuaSubjectProjection[];
604
+ aggregateSubject: CuaSubjectProjection;
605
+ descriptor: CuaActorDescriptor;
606
+ appUrl: string;
607
+ createdAt: string;
608
+ dryRun: boolean;
609
+ config: LabConfig;
610
+ runId: string;
611
+ source: RunBundle["source"];
612
+ plan: CuaLanePlan;
613
+ rerun?: RunRerunLineage;
614
+ failFastReason?: string;
615
+ cloneRoute: boolean;
616
+ localTreeRoute?: boolean;
617
+ publicRepo?: string;
618
+ subjectEnvNames: string[];
619
+ inProgress?: boolean;
620
+ }): RunBundle;