humanish 0.111.1 → 0.111.3

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 (78) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/CHANGELOG.md +29 -0
  3. package/dist/cli/commands/study-route-computer-use.js +3 -8
  4. package/dist/cli/commands/study-route-preview.js +4 -6
  5. package/dist/cli/commands/study-route-shared-world.js +6 -7
  6. package/dist/evidence/redaction.d.ts +2 -2
  7. package/dist/evidence/redaction.js +3 -3
  8. package/dist/observer-app.html +6 -6
  9. package/dist/routes/computer-use/bundle-parts.d.ts +1 -32
  10. package/dist/routes/computer-use/bundle-parts.js +5 -92
  11. package/dist/routes/computer-use/e2b-desktop/prepare.js +11 -4
  12. package/dist/routes/computer-use/fanout-bundle.js +3 -2
  13. package/dist/routes/computer-use/live-phase.js +3 -7
  14. package/dist/routes/computer-use/participant-deps.d.ts +46 -0
  15. package/dist/routes/computer-use/participant-deps.js +48 -0
  16. package/dist/routes/computer-use/participant-facts.d.ts +5 -4
  17. package/dist/routes/computer-use/participant-facts.js +37 -2
  18. package/dist/routes/computer-use/participant-feedback.d.ts +33 -0
  19. package/dist/routes/computer-use/participant-feedback.js +92 -0
  20. package/dist/routes/computer-use/participant-model.d.ts +11 -0
  21. package/dist/routes/computer-use/participant-model.js +15 -0
  22. package/dist/routes/computer-use/preflight.js +33 -65
  23. package/dist/routes/computer-use/result.js +13 -52
  24. package/dist/routes/computer-use/route.js +6 -7
  25. package/dist/routes/computer-use/setup.d.ts +2 -6
  26. package/dist/routes/computer-use/setup.js +47 -93
  27. package/dist/routes/computer-use/single-bundle.js +3 -2
  28. package/dist/routes/computer-use/types.d.ts +2 -2
  29. package/dist/routes/preview.js +2 -8
  30. package/dist/routes/scripted/bundle.d.ts +2 -6
  31. package/dist/routes/scripted/result.d.ts +2 -1
  32. package/dist/routes/scripted/result.js +4 -4
  33. package/dist/routes/scripted/route.js +13 -38
  34. package/dist/routes/scripted/setup.d.ts +2 -1
  35. package/dist/routes/scripted/setup.js +21 -28
  36. package/dist/routes/scripted/subject.d.ts +3 -18
  37. package/dist/routes/scripted/subject.js +22 -78
  38. package/dist/routes/scripted/types.d.ts +2 -2
  39. package/dist/routes/shared-world/bundle.js +36 -1
  40. package/dist/routes/shared-world/comms.d.ts +2 -1
  41. package/dist/routes/shared-world/comms.js +3 -7
  42. package/dist/routes/shared-world/handoff.d.ts +2 -2
  43. package/dist/routes/shared-world/handoff.js +1 -1
  44. package/dist/routes/shared-world/participant-specs.d.ts +4 -5
  45. package/dist/routes/shared-world/participant-specs.js +19 -25
  46. package/dist/routes/shared-world/plan.js +11 -7
  47. package/dist/routes/shared-world/provisioned.d.ts +2 -1
  48. package/dist/routes/shared-world/provisioned.js +37 -80
  49. package/dist/routes/shared-world/result.js +17 -35
  50. package/dist/routes/shared-world/route.js +33 -36
  51. package/dist/routes/shared-world/setup.d.ts +2 -3
  52. package/dist/routes/shared-world/setup.js +11 -29
  53. package/dist/routes/shared-world/types.d.ts +6 -15
  54. package/dist/routes/terminal/dry-run.js +14 -24
  55. package/dist/routes/terminal/live-finish.d.ts +0 -1
  56. package/dist/routes/terminal/live-finish.js +2 -2
  57. package/dist/routes/terminal/route.js +9 -15
  58. package/dist/routes/terminal/session.d.ts +2 -3
  59. package/dist/routes/terminal/session.js +28 -40
  60. package/dist/routes/terminal/trace.d.ts +1 -1
  61. package/dist/routes/terminal/types.d.ts +2 -2
  62. package/dist/run/run.d.ts +55 -1
  63. package/dist/run/run.js +38 -2
  64. package/dist/run/secrets.d.ts +22 -0
  65. package/dist/run/secrets.js +33 -0
  66. package/dist/run/study-result.d.ts +34 -0
  67. package/dist/run/study-result.js +16 -0
  68. package/dist/study/requirements.d.ts +60 -5
  69. package/dist/study/requirements.js +88 -2
  70. package/dist/study/run-study-events.d.ts +4 -3
  71. package/dist/study/run-study-events.js +9 -14
  72. package/dist/study/run-study-options.d.ts +4 -1
  73. package/dist/study/run-study-options.js +22 -32
  74. package/dist/substrates/e2b/subject-sandbox.d.ts +58 -0
  75. package/dist/substrates/e2b/subject-sandbox.js +94 -0
  76. package/docs/contracts/core.md +5 -4
  77. package/docs/contracts/feedback.md +12 -5
  78. package/package.json +1 -1
package/ARCHITECTURE.md CHANGED
@@ -129,7 +129,7 @@ comments name an invariant by its rule.
129
129
  | The run bundle is the source of truth, and the Observer derives from it | `verifyRun` grades only `run.json` and its artifacts (`src/verify/verify.ts`). It reads `status.json` and the sandbox and reclaim receipts only for the `RUN_NOT_FINISHED` warning (`runNotFinished` in `src/verify/liveness.ts`), which changes no check and no grade. `buildObserverData` takes the bundle (`src/observer/data.ts`) | `tests/observer/data-contract.test.ts`; `tests/verify/run-not-finished.test.ts` checks that the grades are the same when `status.json` contradicts the bundle or is gone; `docs/decisions/0001-run-bundle-is-the-source-of-truth.md` |
130
130
  | Unsupported execution is refused before side effects | `parseStudy` (`src/study/config.ts`), `taskProtocolValidationReason` (`src/study/validation.ts`), `planComputerUseStudy` (`src/routes/computer-use/plan.ts`) | `tests/admission/library.test.ts` checks each library refusal for a run directory, a desktop module load, a caller executor or provider, and a subprocess; `tests/admission/cli.test.ts` checks each CLI refusal for a run directory, a started process and a scorer's host code; `tests/study/task-route-preflight.test.ts`; `pnpm cli:preflight:test` runs `scripts/task-route-preflight-proof.mjs` with `tests/fixtures/task-route-preflight/deny-side-effects.mjs` preloaded |
131
131
  | A sandbox id is recorded before any work runs in it | `acquireE2BDesktopSandbox` and `acquireE2BShellSandbox` (`src/substrates/e2b/sandbox.ts`) tag the sandbox with its run's owner tags, register the create with `beginSandboxCreate` (`src/run/sandbox-creates.ts`) and write the receipt before they return the handle, and every route that creates a sandbox calls them; `reclaimRunSandboxes` (`src/run/reclaim.ts`) switches on the receipt's provider, kills by exact id and by the run's exact tags | `tests/substrates/e2b/sandbox.test.ts`, which also checks that `Sandbox.create` has one call site in `src/`, `tests/routes/terminal/acquisition-boundary.test.ts`, `tests/run/reclaim.test.ts`; `tests/routes/scripted/route.test.ts` checks create, receipt, then first work |
132
- | Bundles carry no secrets | `redactText` and `scrubLiterals` (`src/evidence/redaction.ts`); `scanRunPublicSafetyArtifacts` (`src/verify/artifacts.ts`); `buildShareSafety` (`src/verify/verify.ts`) grades `share_ready`, `local_only` or `blocked` | `tests/evidence/redaction-hooks.test.ts`, `tests/run/transient-comms-secrets.test.ts`, `tests/verify/evidence-refs.test.ts` |
132
+ | Bundles carry no secrets | `redactText` and `scrubLiterals` (`src/evidence/redaction.ts`); `RunSecrets` (`src/run/secrets.ts`) holds the literal values each run scrubs; `scanRunPublicSafetyArtifacts` (`src/verify/artifacts.ts`); `buildShareSafety` (`src/verify/verify.ts`) grades `share_ready`, `local_only` or `blocked` | `tests/evidence/redaction-hooks.test.ts`, `tests/routes/known-secrets.test.ts`, `tests/run/transient-comms-secrets.test.ts`, `tests/verify/evidence-refs.test.ts` |
133
133
  | Goldens pin route output | `runDirSnapshot` (`tests/helpers/run-golden.ts`) snapshots a whole run folder | `tests/golden/routes/`, `tests/golden/observer-data/`, `tests/golden/labs/`; `tests/study/plan-lab.test.ts` checks that every `StudyRoute` has a dry-run golden |
134
134
  | A run is closed on every exit, only a published run is analyzed, and `latest.json` moves only after its run is published | `runScope` and `FinishedRun` (`src/run/run.ts`); `completeAutomaticAnalysis` requires an issued `FinishedRun` for the result's run; `Run.finish` writes `latest.json` last through `writePreparedRunLatestPointer` (`src/run/contained-output.ts`) | `tests/run/run-lifecycle.test.ts`, which also checks that `src/run/run.ts` is the pointer's one writer, `tests/analysis/automatic-analysis.test.ts` |
135
135
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,35 @@ The Unreleased section holds the full notes for the next version until it is tag
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## 0.111.3: Shared-world feedback candidates, scripted E2B key scrubbed, subject sandbox warnings (2026-10-06)
12
+
13
+ humanish 0.111.3 gives shared-world runs feedback candidates and repairs seven places where one
14
+ route's warnings, refusals, secret scrubbing or run directory checks differed from the other
15
+ routes'. A shared-world participant who reports friction or gives up becomes a candidate that
16
+ `humanish feedback` drafts, and each candidate from a run with several participants shows that
17
+ participant's own instructions as `expected`. A scripted run scrubs the value of `E2B_API_KEY` from
18
+ the errors and subject setup output it records, and writes `[REDACTED_SECRET]` where it wrote
19
+ `[redacted]`. A shared-world study with `caps.maxUsd` and no `caps.maxTotalUsd` warns that the cap
20
+ applies to each participant. The subject sandbox of a scripted clone study or a provisioned
21
+ shared-world study warns when its create was retried or E2B reports no size. A scripted clone study
22
+ missing a `subject.env` value, and a provisioned shared-world study missing `OPENAI_API_KEY`,
23
+ refuse with the wording computer use gives. Computer-use and shared-world runs check the run
24
+ directory again after a `prepareDesktop` hook and an Observer render.
25
+
26
+ [Release notes](https://github.com/danielgwilson/humanish/releases/tag/v0.111.3)
27
+
28
+ ## 0.111.2: A taller Observer frame, even grid cards, a notice when the server stops (2026-10-06)
29
+
30
+ humanish 0.111.2 changes the Observer and nothing else. The focus view's heading line holds the
31
+ Back button, the participant pager, the name, the status and the inspector toggle, and the assigned
32
+ task and participant background move into the Details tab, so the frame at 1600x1000 is 171 px
33
+ taller. Every grid card has a 44 px caption, so phone-sized and desktop cards in one row end at the
34
+ same height. An open Observer page whose server stopped shows one notice with the run id and two
35
+ ways back to the recording, where 0.111.1 showed "Frame unavailable" on every tile. The CLI, the
36
+ library and the study routes are the same as in 0.111.1.
37
+
38
+ [Release notes](https://github.com/danielgwilson/humanish/releases/tag/v0.111.2)
39
+
11
40
  ## 0.111.1: E2B URLs in study URLs, fan-out dry runs verify, zero-data-retention cache holds (2026-10-06)
12
41
 
13
42
  humanish 0.111.1 fixes a study URL refusal and two verify problems that an adopter met on 0.111.0,
@@ -12,7 +12,7 @@ import { exposureRequestFromOptions, followDecision, followObserver, planObserve
12
12
  import { writeRunFindings } from "../findings.js";
13
13
  import { formatCuaStudyHuman } from "./study-format.js";
14
14
  import { resolveRouteShouldOpen } from "./study-route-open.js";
15
- import { studyResultIdentity } from "../../run/study-result.js";
15
+ import { refusedResult } from "../../run/study-result.js";
16
16
  import { declaredParticipantCount } from "../../study/study-fields.js";
17
17
  /**
18
18
  * The computer-use route's CLI setup: its settings, the watch and exposure plan, the runStudyWith options
@@ -51,17 +51,12 @@ export function computerUseRouteRun(args) {
51
51
  };
52
52
  }
53
53
  function refuseCua(args, dryRun, code, message) {
54
- const result = {
55
- ...studyResultIdentity("computer-use", args.config.id),
56
- ok: false,
57
- cwd: args.options.cwd,
54
+ const result = refusedResult("computer-use", { studyId: args.config.id, cwd: args.options.cwd, error: { code, message } }, {
58
55
  actor: args.config.actor?.type ?? "",
59
56
  appUrl: "",
60
57
  dryRun,
61
58
  runId: args.options.runId ?? "not-created",
62
- warnings: [],
63
- error: { code, message },
64
- };
59
+ });
65
60
  writeResult(args.command, args.io, result, formatCuaStudyHuman);
66
61
  args.io.setExitCode(2);
67
62
  }
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import { studyResultIdentity } from "../../run/study-result.js";
2
+ import { refusedResult } from "../../run/study-result.js";
3
3
  import { formatRunHuman, parseStudyCount, writeResult, } from "../io.js";
4
4
  import { planObserver, showObserver, staticObserverOpen } from "../observer-follow.js";
5
5
  import { declaredParticipantCount } from "../../study/study-fields.js";
@@ -10,16 +10,14 @@ import { declaredParticipantCount } from "../../study/study-fields.js";
10
10
  export function previewRouteRun(args) {
11
11
  const participantCount = parseStudyCount(args.options.count, declaredParticipantCount(args.config) ?? 4);
12
12
  if (participantCount === null) {
13
- const result = {
14
- ...studyResultIdentity("preview", args.config.id),
15
- ok: false,
13
+ const result = refusedResult("preview", {
14
+ studyId: args.config.id,
16
15
  cwd: args.options.cwd,
17
- warnings: [],
18
16
  error: {
19
17
  code: "HUMANISH_INVALID_PARTICIPANT_COUNT",
20
18
  message: "--count must be a positive integer.",
21
19
  },
22
- };
20
+ }, {});
23
21
  writeResult(args.command, args.io, result, formatRunHuman);
24
22
  args.io.setExitCode(2);
25
23
  return undefined;
@@ -9,7 +9,7 @@ import { followDecision, followObserver, showObserver, staticObserverOpen, withO
9
9
  import { writeRunFindings } from "../findings.js";
10
10
  import { formatConcurrentSharedWorldStudyHuman } from "./study-format.js";
11
11
  import { resolveRouteShouldOpen, watchFinishedPlan } from "./study-route-open.js";
12
- import { studyResultIdentity } from "../../run/study-result.js";
12
+ import { refusedResult } from "../../run/study-result.js";
13
13
  import { participantList } from "../../study/study-fields.js";
14
14
  /**
15
15
  * The shared-world route's CLI setup: dry run, open and follow semantics, the live Observer server
@@ -30,10 +30,11 @@ export function sharedWorldRouteRun(args) {
30
30
  followDecision({ wantsMachine, detach: args.options.detach, serve: args.options.serve }).follow;
31
31
  const port = parseObserverPort(args.options.port ?? "0");
32
32
  const failConcurrent = (message, runId) => {
33
- const result = {
34
- ...studyResultIdentity("shared-world", args.config.id),
35
- ok: false,
33
+ const result = refusedResult("shared-world", {
34
+ studyId: args.config.id,
36
35
  cwd: args.options.cwd,
36
+ error: { code: "HUMANISH_SHARED_WORLD_FAILED", message },
37
+ }, {
37
38
  actor: args.config.actor?.type ?? "",
38
39
  topology: "shared-world",
39
40
  topologyMode: "concurrent",
@@ -42,9 +43,7 @@ export function sharedWorldRouteRun(args) {
42
43
  dryRun,
43
44
  runId: runId ?? args.options.runId ?? "not-created",
44
45
  roles: [],
45
- warnings: [],
46
- error: { code: "HUMANISH_SHARED_WORLD_FAILED", message },
47
- };
46
+ });
48
47
  writeResult(args.command, args.io, result, formatConcurrentSharedWorldStudyHuman);
49
48
  args.io.setExitCode(2);
50
49
  };
@@ -112,11 +112,11 @@ export interface RedactionHooks {
112
112
  /** The default hooks wired into every actor: redaction.ts is the source of truth. */
113
113
  export declare const defaultRedactionHooks: RedactionHooks;
114
114
  /**
115
- * Replace each literal value with [REDACTED_SECRET]. For values that have no secret shape to
115
+ * Replace each literal value with `marker`. For values that have no secret shape to
116
116
  * pattern-match, such as provisioned keys and subject env values. `values` is read on each call,
117
117
  * so a value registered later is scrubbed too.
118
118
  */
119
- export declare function scrubLiterals(values: readonly string[]): (text: string) => string;
119
+ export declare function scrubLiterals(values: readonly string[], marker?: string): (text: string) => string;
120
120
  /**
121
121
  * Coerce an unknown thrown value to its message string. Prefer this over the
122
122
  * inline `error instanceof Error ? error.message : String(error)` so error
@@ -522,12 +522,12 @@ function blurPass(src, width, height, radius, horizontal) {
522
522
  return out;
523
523
  }
524
524
  /**
525
- * Replace each literal value with [REDACTED_SECRET]. For values that have no secret shape to
525
+ * Replace each literal value with `marker`. For values that have no secret shape to
526
526
  * pattern-match, such as provisioned keys and subject env values. `values` is read on each call,
527
527
  * so a value registered later is scrubbed too.
528
528
  */
529
- export function scrubLiterals(values) {
530
- return (text) => values.reduce((current, value) => current.split(value).join("[REDACTED_SECRET]"), text);
529
+ export function scrubLiterals(values, marker = "[REDACTED_SECRET]") {
530
+ return (text) => values.reduce((current, value) => current.split(value).join(marker), text);
531
531
  }
532
532
  /**
533
533
  * Coerce an unknown thrown value to its message string. Prefer this over the