humanish 0.111.4 → 0.112.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 (93) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/actors/computer-use/openai-conversation.d.ts +91 -0
  3. package/dist/actors/computer-use/openai-conversation.js +209 -0
  4. package/dist/actors/computer-use/openai-provider.js +25 -41
  5. package/dist/actors/contract.d.ts +2 -0
  6. package/dist/analysis/diagnostics.js +7 -12
  7. package/dist/analysis/execute.d.ts +1 -1
  8. package/dist/analysis/execute.js +35 -5
  9. package/dist/analysis/service.js +7 -1
  10. package/dist/analysis/types.d.ts +23 -0
  11. package/dist/analysis/validation.d.ts +80 -35
  12. package/dist/analysis/validation.js +58 -11
  13. package/dist/cli/commands/runs.js +4 -10
  14. package/dist/cli/findings.d.ts +34 -3
  15. package/dist/cli/findings.js +136 -18
  16. package/dist/cli/io.d.ts +2 -1
  17. package/dist/cli/io.js +3 -2
  18. package/dist/feedback/draft.js +14 -4
  19. package/dist/observer/run-routes.js +8 -4
  20. package/dist/observer-app.html +4 -4
  21. package/dist/routes/computer-use/bundle.d.ts +1 -1
  22. package/dist/routes/computer-use/bundle.js +6 -16
  23. package/dist/routes/computer-use/fanout-bundle.js +40 -37
  24. package/dist/routes/computer-use/fanout-records.d.ts +2 -0
  25. package/dist/routes/computer-use/fanout-records.js +18 -26
  26. package/dist/routes/computer-use/participant-execution.js +4 -11
  27. package/dist/routes/computer-use/participant-facts.d.ts +2 -2
  28. package/dist/routes/computer-use/participant-facts.js +10 -1
  29. package/dist/routes/computer-use/result.js +7 -15
  30. package/dist/routes/computer-use/single-bundle.d.ts +2 -0
  31. package/dist/routes/computer-use/single-bundle.js +81 -37
  32. package/dist/routes/scripted/bundle.d.ts +1 -1
  33. package/dist/routes/scripted/bundle.js +9 -19
  34. package/dist/routes/scripted/surface-records.d.ts +0 -1
  35. package/dist/routes/scripted/surface-records.js +27 -13
  36. package/dist/routes/shared-world/bundle-records.d.ts +2 -2
  37. package/dist/routes/shared-world/bundle-records.js +21 -28
  38. package/dist/routes/shared-world/bundle.d.ts +1 -1
  39. package/dist/routes/shared-world/bundle.js +70 -78
  40. package/dist/routes/shared-world/participant-specs.d.ts +1 -2
  41. package/dist/routes/shared-world/participant-specs.js +0 -8
  42. package/dist/routes/shared-world/result.js +8 -12
  43. package/dist/routes/terminal/bundle.d.ts +1 -1
  44. package/dist/routes/terminal/bundle.js +10 -19
  45. package/dist/routes/terminal/dry-run.js +1 -0
  46. package/dist/routes/terminal/live-sandbox.js +9 -2
  47. package/dist/routes/terminal/plan.js +1 -0
  48. package/dist/routes/terminal/runtime.d.ts +1 -0
  49. package/dist/routes/terminal/runtime.js +1 -0
  50. package/dist/routes/terminal/session.js +1 -0
  51. package/dist/run/costs.js +9 -20
  52. package/dist/run/detail.d.ts +1 -1
  53. package/dist/run/detail.js +10 -1
  54. package/dist/run/display.d.ts +2 -2
  55. package/dist/run/display.js +15 -18
  56. package/dist/run/dry-run.js +10 -25
  57. package/dist/run/judge.d.ts +24 -0
  58. package/dist/run/judge.js +54 -0
  59. package/dist/run/liveness.d.ts +18 -0
  60. package/dist/run/liveness.js +24 -0
  61. package/dist/run/outcomes.d.ts +8 -1
  62. package/dist/run/outcomes.js +58 -12
  63. package/dist/run/participant-caption.d.ts +30 -0
  64. package/dist/run/participant-caption.js +50 -0
  65. package/dist/run/participant-records.d.ts +1 -1
  66. package/dist/run/review-markdown.d.ts +11 -0
  67. package/dist/run/review-markdown.js +22 -0
  68. package/dist/run/run-cost.d.ts +7 -0
  69. package/dist/run/run-cost.js +25 -5
  70. package/dist/run/run-index.d.ts +4 -50
  71. package/dist/run/run-index.js +57 -87
  72. package/dist/run/run.d.ts +2 -2
  73. package/dist/run/run.js +5 -3
  74. package/dist/run/stats.js +2 -12
  75. package/dist/run/transient-comms-secrets.d.ts +8 -3
  76. package/dist/run/transient-comms-secrets.js +21 -1
  77. package/dist/study/keys.d.ts +1 -0
  78. package/dist/study/keys.js +1 -1
  79. package/dist/study/parse/execution.js +7 -1
  80. package/dist/study/plan-types.d.ts +1 -0
  81. package/dist/study/types.d.ts +4 -1
  82. package/dist/study/warnings.d.ts +2 -1
  83. package/dist/study/warnings.js +3 -2
  84. package/dist/tui-app.js +73 -73
  85. package/dist/verify/liveness.d.ts +2 -2
  86. package/dist/verify/liveness.js +7 -4
  87. package/docs/architecture/terminal-product-route.md +14 -0
  88. package/docs/contracts/run-bundle.md +10 -0
  89. package/docs/contracts/schemas.md +9 -1
  90. package/docs/contracts/study-analysis.md +71 -22
  91. package/package.json +2 -1
  92. package/dist/actors/computer-use/openai-requests.d.ts +0 -62
  93. package/dist/actors/computer-use/openai-requests.js +0 -144
@@ -4,7 +4,12 @@ export declare function registerTransientCommsSecrets(values: string[]): void;
4
4
  /** Literal, longest-first replacement in one pass; replacement text is never matched recursively. */
5
5
  export declare function scrubTransientCommsText(text: string): string;
6
6
  /**
7
- * The scope's values as a scrubSecretValues scrub, which also finds them percent-encoded, escaped or
8
- * base64-encoded and returns decoded text. Outside a scope it changes nothing.
7
+ * A scrub for text a model writes: each scope value as written and in its encoded forms
8
+ * (percent-encoded, JSON-escaped, base64, base64url, hex), and where escapes split one. Text that
9
+ * holds an encoded value is returned decoded with each value replaced. Text without one keeps its
10
+ * original spelling, so an exact quote that holds an escape still matches its evidence. The literal
11
+ * scrub runs first, before decoding can rewrite a value that itself holds an escape, and last,
12
+ * because the encoded scrub leaves text inside marker-shaped spans alone. Outside a scope it
13
+ * changes nothing.
9
14
  */
10
- export declare function transientCommsEncodedScrub(): (text: string) => string;
15
+ export declare function transientCommsKnownValueScrub(): (text: string) => string;
@@ -1,4 +1,5 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { decodeEscapes } from "../evidence/encoded-text.js";
2
3
  import { scrubSecretValues } from "../evidence/secret-scrub.js";
3
4
  import { escapeRegExp } from "./text.js";
4
5
  const scopes = new AsyncLocalStorage();
@@ -75,10 +76,29 @@ export function scrubTransientCommsText(text) {
75
76
  * The scope's values as a scrubSecretValues scrub, which also finds them percent-encoded, escaped or
76
77
  * base64-encoded and returns decoded text. Outside a scope it changes nothing.
77
78
  */
78
- export function transientCommsEncodedScrub() {
79
+ function transientCommsEncodedScrub() {
79
80
  const scope = scopes.getStore();
80
81
  if (!scope)
81
82
  return (text) => text;
82
83
  usable(scope);
83
84
  return scrubSecretValues([...scope.values]);
84
85
  }
86
+ const REDACTED = "[REDACTED_SECRET]";
87
+ const markers = (text) => text.split(REDACTED).length - 1;
88
+ /**
89
+ * A scrub for text a model writes: each scope value as written and in its encoded forms
90
+ * (percent-encoded, JSON-escaped, base64, base64url, hex), and where escapes split one. Text that
91
+ * holds an encoded value is returned decoded with each value replaced. Text without one keeps its
92
+ * original spelling, so an exact quote that holds an escape still matches its evidence. The literal
93
+ * scrub runs first, before decoding can rewrite a value that itself holds an escape, and last,
94
+ * because the encoded scrub leaves text inside marker-shaped spans alone. Outside a scope it
95
+ * changes nothing.
96
+ */
97
+ export function transientCommsKnownValueScrub() {
98
+ const encoded = transientCommsEncodedScrub();
99
+ return (text) => {
100
+ const literal = scrubTransientCommsText(text);
101
+ const found = encoded(literal);
102
+ return scrubTransientCommsText(markers(found) > markers(decodeEscapes(literal)) ? found : literal);
103
+ };
104
+ }
@@ -168,6 +168,7 @@ export declare const EXECUTION: {
168
168
  terminal: {
169
169
  stdin: true;
170
170
  transport: true;
171
+ doNotTrack: true;
171
172
  };
172
173
  desktop: {
173
174
  template: true;
@@ -108,7 +108,7 @@ export const EXECUTION = {
108
108
  timeoutMs: true,
109
109
  completionTimeoutMs: true,
110
110
  egressAllow: true,
111
- terminal: { stdin: true, transport: true },
111
+ terminal: { stdin: true, transport: true, doNotTrack: true },
112
112
  desktop: {
113
113
  template: true,
114
114
  browser: true,
@@ -75,9 +75,15 @@ function parseTerminal(raw) {
75
75
  return { ok: true, value: undefined };
76
76
  }
77
77
  if (!isRecord(raw)) {
78
- return invalid("`execution.terminal` must be an object ({ transport?, stdin? }).");
78
+ return invalid("`execution.terminal` must be an object ({ transport?, stdin?, doNotTrack? }).");
79
79
  }
80
80
  const terminal = {};
81
+ if (raw.doNotTrack !== undefined) {
82
+ if (typeof raw.doNotTrack !== "boolean") {
83
+ return invalid("`execution.terminal.doNotTrack` must be true or false (unquoted).");
84
+ }
85
+ terminal.doNotTrack = raw.doNotTrack;
86
+ }
81
87
  if (raw.transport !== undefined) {
82
88
  const transport = str(raw.transport);
83
89
  if (transport !== "exec-stream") {
@@ -217,6 +217,7 @@ export type TerminalPlan = PlanBase & {
217
217
  readonly personaId?: string;
218
218
  readonly mission?: string;
219
219
  readonly runtime: {
220
+ readonly doNotTrack: boolean;
220
221
  readonly version?: string;
221
222
  /** Passed to Codex as `--model` on every run, so the bundle can name and price it. */
222
223
  readonly model: string;
@@ -401,6 +401,8 @@ export interface StudyExecutionTerminal {
401
401
  transport?: StudyTerminalTransport;
402
402
  /** Operator stdin posture. Default "disabled". */
403
403
  stdin?: StudyTerminalStdin;
404
+ /** Send DO_NOT_TRACK=1 to participant commands by default; false leaves it unset. */
405
+ doNotTrack?: boolean;
404
406
  }
405
407
  /**
406
408
  * The terminal agent's runtime-auth channel. "openai-egress" (the default) keeps the raw runtime
@@ -511,7 +513,8 @@ export interface StudyExecution {
511
513
  };
512
514
  /**
513
515
  * `terminal-product` route: outbound routing allowlist passed to E2B with a deny-all fallback.
514
- * Every other route leaves egress open and ignores it with a warning; 0.112.0 refuses it there.
516
+ * Every other route leaves egress open and ignores it with a warning;
517
+ * the first minor release on or after 2026-11-04 refuses it there.
515
518
  * Domain filtering is a routing control, not strict destination isolation on shared hosting.
516
519
  * It does not constrain spending through an allowed runtime provider, including when
517
520
  * openai-egress keeps the raw runtime key outside the sandbox.
@@ -14,7 +14,8 @@ export declare function inertFieldPaths(config: StudyConfig): string[];
14
14
  * terminal route creates its sandbox with the list as an outbound allowlist; on any other route the
15
15
  * study author would trust a list that blocks nothing. `humanish study check` and every run print
16
16
  * it, and the run records it in its bundle.
17
- * Removed in 0.112.0: deprecated on 2026-10-05. 0.112.0 refuses the field off the terminal route.
17
+ * Removed in the first minor release on or after 2026-11-04: deprecated on 2026-10-05. That release refuses the field off the terminal
18
+ * route.
18
19
  */
19
20
  export declare function egressAllowIgnoredWarning(config: StudyConfig): string | undefined;
20
21
  export declare function forwardDeclaredWarnings(config: StudyConfig): string[];
@@ -270,12 +270,13 @@ export function inertFieldPaths(config) {
270
270
  * terminal route creates its sandbox with the list as an outbound allowlist; on any other route the
271
271
  * study author would trust a list that blocks nothing. `humanish study check` and every run print
272
272
  * it, and the run records it in its bundle.
273
- * Removed in 0.112.0: deprecated on 2026-10-05. 0.112.0 refuses the field off the terminal route.
273
+ * Removed in the first minor release on or after 2026-11-04: deprecated on 2026-10-05. That release refuses the field off the terminal
274
+ * route.
274
275
  */
275
276
  export function egressAllowIgnoredWarning(config) {
276
277
  if (config.execution?.egressAllow === undefined || config.route === "terminal")
277
278
  return undefined;
278
- return `\`execution.egressAllow\` is ignored on route: ${config.route}. Only route: terminal creates its sandbox with that outbound allowlist, and this route's browser desktops can reach any site. Remove the field: humanish 0.112.0 refuses it on every route except terminal.`;
279
+ return `\`execution.egressAllow\` is ignored on route: ${config.route}. Only route: terminal creates its sandbox with that outbound allowlist, and this route's browser desktops can reach any site. Remove the field: the first minor release on or after 2026-11-04 refuses it on every route except terminal.`;
279
280
  }
280
281
  // Report fields that are present but not yet consumed by the engine, so a user never trusts a
281
282
  // setting that silently does nothing.