humanish 0.106.0 → 0.106.1

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 (40) hide show
  1. package/AGENTS.md +3 -1
  2. package/CHANGELOG.md +10 -0
  3. package/CONTRIBUTING.md +4 -2
  4. package/dist/actors/codex/qualified-versions.d.ts +1 -1
  5. package/dist/actors/codex/qualified-versions.js +1 -1
  6. package/dist/actors/contract.d.ts +1 -1
  7. package/dist/actors/contract.js +7 -1
  8. package/dist/lab/composition-rules.d.ts +2 -0
  9. package/dist/lab/composition-rules.js +15 -6
  10. package/dist/lab/plan-base.d.ts +6 -0
  11. package/dist/lab/plan-base.js +16 -3
  12. package/dist/lab/plan-types.d.ts +12 -4
  13. package/dist/observer-app.html +1 -1
  14. package/dist/routes/computer-use/participant-model.js +10 -9
  15. package/dist/routes/computer-use/plan.js +7 -5
  16. package/dist/routes/computer-use/preflight.d.ts +3 -6
  17. package/dist/routes/computer-use/preflight.js +11 -7
  18. package/dist/routes/computer-use/route.d.ts +3 -3
  19. package/dist/routes/computer-use/route.js +3 -3
  20. package/dist/routes/computer-use/run-lanes.js +3 -3
  21. package/dist/routes/computer-use/setup.d.ts +0 -3
  22. package/dist/routes/computer-use/setup.js +3 -15
  23. package/dist/routes/computer-use/types.d.ts +3 -4
  24. package/dist/routes/computer-use/types.js +0 -1
  25. package/dist/routes/scripted/subject.js +2 -1
  26. package/dist/routes/shared-world/provisioned.js +2 -1
  27. package/dist/routes/shared-world/seats.js +3 -3
  28. package/dist/routes/terminal/live-sandbox.d.ts +1 -0
  29. package/dist/routes/terminal/live-sandbox.js +5 -1
  30. package/dist/routes/terminal/sandbox.d.ts +2 -0
  31. package/dist/routes/terminal/sandbox.js +4 -7
  32. package/dist/run/reclaim.d.ts +1 -1
  33. package/dist/run/reclaim.js +11 -1
  34. package/dist/substrates/desktop-session.d.ts +2 -0
  35. package/dist/substrates/e2b/sandbox.d.ts +2 -0
  36. package/dist/substrates/e2b/sandbox.js +21 -7
  37. package/dist/substrates/e2b/sdk.d.ts +12 -1
  38. package/dist/substrates/e2b/sdk.js +28 -7
  39. package/docs/architecture/restricted-codex-analysis.md +4 -2
  40. package/package.json +2 -2
package/AGENTS.md CHANGED
@@ -35,7 +35,9 @@ diff.
35
35
  Three counts are held to caps in package.json: oxlint warnings (`lint`, `--max-warnings`), comment
36
36
  prose (`prose:check`) and the retired words lane, seat, role, sim and study in `src/` identifiers
37
37
  (`vocabulary:check`). Each checker fails when a count is above its cap or below it, so the PR that
38
- reduces a count lowers its cap to the new count; the failure names the flag and the value.
38
+ reduces a count lowers its cap to the new count; the failure names the flag and the value. CI's
39
+ `caps` workflow fails a PR that raises or removes a cap against the base branch, unless the PR has
40
+ the `raise-cap` label and a `Cap raise:` line in its body that says why.
39
41
 
40
42
  ## Layout
41
43
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,16 @@ The Unreleased section holds the full notes for the next version until it is tag
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## 0.106.1: Codex CLI 0.160.0 and reclaim in E2B debug mode (2026-10-01)
12
+
13
+ Codex participants, Codex-account analysis and `humanish doctor` admit Codex CLI 0.160.0 (published
14
+ to npm 2026-10-01) on Linux x64, which 0.106.0 refused. Doctor's recovery for an unadmitted release
15
+ suggests `npm install -g @openai/codex@0.160.0`. `humanish reclaim` refuses to run with
16
+ `E2B_DEBUG=true`, where the E2B SDK reports kills it never sent, and a run's sandbox teardown in
17
+ debug mode reads unconfirmed.
18
+
19
+ [Release notes](https://github.com/danielgwilson/humanish/releases/tag/v0.106.1)
20
+
11
21
  ## 0.106.0: Node 22.19, a smaller library API and stricter share safety (2026-10-01)
12
22
 
13
23
  humanish needs Node 22.19.0 or later. The library entry point exports 83 names, down from 377:
package/CONTRIBUTING.md CHANGED
@@ -72,8 +72,10 @@ comments (`prose:check`: issue references, `FIX-N` tags, all-caps emphasis), and
72
72
  `src/` outside the exempt contract modules that still say lane, seat, role, sim or study
73
73
  (`vocabulary:check`). Each check fails when its count rises above the cap and also when it falls
74
74
  below it, so the PR that reduces a count lowers the cap in the same commit; the failure message
75
- names the flag and the new value. `pnpm lint` prints the warnings that already exist, several
76
- hundred of them; that is expected. `pnpm knip` fails on unused files,
75
+ names the flag and the new value. CI's `caps` workflow (`scripts/check-cap-direction.mjs`) also
76
+ fails a PR that raises or removes a cap against the base branch, unless the PR has the `raise-cap`
77
+ label and a `Cap raise:` line in its body that says why. `pnpm lint` prints the warnings that
78
+ already exist, several hundred of them; that is expected. `pnpm knip` fails on unused files,
77
79
  dependencies and exports, and on any import cycle.
78
80
 
79
81
  ## Useful Commands
@@ -10,7 +10,7 @@
10
10
  * of them.
11
11
  */
12
12
  export declare const QUALIFIED_CODEX_CLI_VERSIONS: {
13
- readonly "linux-x64": readonly ["0.154.0", "0.157.1", "0.159.2", "0.159.3"];
13
+ readonly "linux-x64": readonly ["0.154.0", "0.157.1", "0.159.2", "0.159.3", "0.160.0"];
14
14
  readonly "darwin-arm64": readonly ["0.154.0"];
15
15
  };
16
16
  /**
@@ -10,7 +10,7 @@
10
10
  * of them.
11
11
  */
12
12
  export const QUALIFIED_CODEX_CLI_VERSIONS = {
13
- "linux-x64": ["0.154.0", "0.157.1", "0.159.2", "0.159.3"],
13
+ "linux-x64": ["0.154.0", "0.157.1", "0.159.2", "0.159.3", "0.160.0"],
14
14
  "darwin-arm64": ["0.154.0"],
15
15
  };
16
16
  /**
@@ -140,7 +140,7 @@ export interface ActorTokenUsage {
140
140
  * Codex CLI releases a recorded account profile may name. Append-only: a release can leave the
141
141
  * launch lists in codex/qualified-versions.ts, but saved bundles naming it stay readable.
142
142
  */
143
- export declare const RECORDED_CODEX_CLI_VERSIONS: readonly ["0.154.0", "0.157.1", "0.159.2", "0.159.3"];
143
+ export declare const RECORDED_CODEX_CLI_VERSIONS: readonly ["0.154.0", "0.157.1", "0.159.2", "0.159.3", "0.160.0"];
144
144
  export type RecordedCodexCliVersion = (typeof RECORDED_CODEX_CLI_VERSIONS)[number];
145
145
  export declare function isRecordedCodexCliVersion(value: unknown): value is RecordedCodexCliVersion;
146
146
  /** Requested execution profile; per-request verification is recorded separately. */
@@ -58,7 +58,13 @@ export const ACTOR_STOP_CAUSES = [
58
58
  * Codex CLI releases a recorded account profile may name. Append-only: a release can leave the
59
59
  * launch lists in codex/qualified-versions.ts, but saved bundles naming it stay readable.
60
60
  */
61
- export const RECORDED_CODEX_CLI_VERSIONS = ["0.154.0", "0.157.1", "0.159.2", "0.159.3"];
61
+ export const RECORDED_CODEX_CLI_VERSIONS = [
62
+ "0.154.0",
63
+ "0.157.1",
64
+ "0.159.2",
65
+ "0.159.3",
66
+ "0.160.0",
67
+ ];
62
68
  export function isRecordedCodexCliVersion(value) {
63
69
  return RECORDED_CODEX_CLI_VERSIONS.some((version) => version === value);
64
70
  }
@@ -3,3 +3,5 @@ import type { LabConfig } from "./types.js";
3
3
  export declare function compositionReason(config: LabConfig): string | null;
4
4
  /** Why a this-repo lab cannot run live. The parser and the preview planner both refuse with it. */
5
5
  export declare const THIS_REPO_DRY_RUN_ONLY = "this-repo labs are dry-run only; use a clone or app-url subject for a live run.";
6
+ /** A desktop-cli subject with no product to study. The computer-use planner checks this too. */
7
+ export declare function desktopCliProductReason(config: LabConfig): string | null;
@@ -1,7 +1,10 @@
1
1
  // Which subject, target and actor compositions a lab may declare. Each rule returns the refusal
2
2
  // message for the first thing its composition gets wrong, or null. compositionReason runs them in
3
- // the parser's order; parseLabConfig calls it after the structural parse, and the planLab design
4
- // has library callers go through the same function.
3
+ // the parser's order, and only parseLabConfig calls it. planLab does not: each route planner checks
4
+ // a library caller's config itself, under its route's error codes. The planners call the shared
5
+ // checks in lab/validation.ts and desktopCliProductReason below. The other subject rules here have
6
+ // planner counterparts whose conditions and wording differ (clone serve and repo, local-tree
7
+ // target, in-process fan-out, loopback targets, scripted scenario.ref).
5
8
  import { isLoopbackUrl } from "./parse/subject.js";
6
9
  import { REPO_SLUG_PATTERN } from "./parse/values.js";
7
10
  import { declaredTargets } from "./plan-participants.js";
@@ -221,11 +224,17 @@ function localTreeValidationReason(config) {
221
224
  //
222
225
  // Fail-closed on the pairing (invariant 6): a hosted desktop and a computer-use actor, because
223
226
  // "watch a person use a terminal" is not something the other substrates can do.
227
+ /** A desktop-cli subject with no product to study. The computer-use planner checks this too. */
228
+ export function desktopCliProductReason(config) {
229
+ return config.subject.source === "desktop-cli" && config.subject.product?.name === undefined
230
+ ? "desktop-cli subjects need `subject.product.name` — the CLI the participant is being asked to use."
231
+ : null;
232
+ }
224
233
  function desktopCliValidationReason(config) {
225
- if (config.subject.source === "desktop-cli") {
226
- if (config.subject.product?.name === undefined) {
227
- return "desktop-cli subjects need `subject.product.name` — the CLI the participant is being asked to use.";
228
- }
234
+ const productReason = desktopCliProductReason(config);
235
+ if (productReason)
236
+ return productReason;
237
+ if (config.subject.source === "desktop-cli" && config.subject.product !== undefined) {
229
238
  if (config.execution?.target !== undefined && config.execution.target !== "e2b-desktop") {
230
239
  return "desktop-cli subjects are studied at a hosted desktop — set `execution.target: e2b-desktop` or omit it.";
231
240
  }
@@ -13,6 +13,12 @@ export declare function desktopRequirements(config: LabConfig, args: {
13
13
  externalCatch: boolean;
14
14
  }): Requirement[];
15
15
  export declare function brainOf(config: LabConfig, callerProvider: boolean): Brain;
16
+ /** The brain of a run whose provider the library caller supplies. */
17
+ export declare function callerBrainOf(config: LabConfig): Extract<Brain, {
18
+ kind: "caller";
19
+ }>;
20
+ /** The model a participant's spend is priced at when its provider reports none. */
21
+ export declare function pricedModel(brain: Brain): string;
16
22
  /** The fields every plan shares, from a config whose analysis already resolved. */
17
23
  export declare function planBase(config: LabConfig, input: {
18
24
  readonly dryRun: boolean;
@@ -85,10 +85,23 @@ export function desktopRequirements(config, args) {
85
85
  export function brainOf(config, callerProvider) {
86
86
  const actor = config.actors[0];
87
87
  if (callerProvider)
88
- return { kind: "caller" };
88
+ return callerBrainOf(config);
89
+ const declared = declaredModelOf(config);
89
90
  if (actor?.type === "local-agent")
90
- return { kind: "local-agent", agent: actor.localAgent ?? "codex" };
91
- return { kind: "openai", model: actor?.model ?? DEFAULT_OPENAI_CU_MODEL };
91
+ return { kind: "local-agent", agent: actor.localAgent ?? "codex", ...declared };
92
+ return { kind: "openai", model: actor?.model ?? DEFAULT_OPENAI_CU_MODEL, ...declared };
93
+ }
94
+ /** The brain of a run whose provider the library caller supplies. */
95
+ export function callerBrainOf(config) {
96
+ return { kind: "caller", ...declaredModelOf(config) };
97
+ }
98
+ function declaredModelOf(config) {
99
+ const model = config.actors[0]?.model;
100
+ return model === undefined ? {} : { declaredModel: model };
101
+ }
102
+ /** The model a participant's spend is priced at when its provider reports none. */
103
+ export function pricedModel(brain) {
104
+ return brain.declaredModel ?? DEFAULT_OPENAI_CU_MODEL;
92
105
  }
93
106
  /** The fields every plan shares, from a config whose analysis already resolved. */
94
107
  export function planBase(config, input) {
@@ -73,15 +73,23 @@ interface PreviewPlan extends PlanBase {
73
73
  /** A safe integer of at least 1. */
74
74
  readonly participantCount: number;
75
75
  }
76
- /** The model driving a desktop participant. `caller` is the library caller's buildProvider. */
76
+ /**
77
+ * The model driving a desktop participant. `caller` is the library caller's buildProvider.
78
+ * `declaredModel` is actors[0].model as the lab wrote it, absent when undeclared: the providers
79
+ * take it as written, and spend is priced at it, else the default (pricedModel). An openai
80
+ * brain's `model` is the one its provider runs, with that default applied.
81
+ */
77
82
  export type Brain = {
78
83
  readonly kind: "openai";
79
84
  readonly model: string;
85
+ readonly declaredModel?: string;
80
86
  } | {
81
87
  readonly kind: "local-agent";
82
88
  readonly agent: LocalAgentId;
89
+ readonly declaredModel?: string;
83
90
  } | {
84
91
  readonly kind: "caller";
92
+ readonly declaredModel?: string;
85
93
  };
86
94
  export type ProvisionedSubject = {
87
95
  readonly kind: "clone";
@@ -121,9 +129,9 @@ export type ComputerUseRunner = {
121
129
  /** The caller's executor and provider together; one participant. */
122
130
  | {
123
131
  readonly desktop: "in-process";
124
- readonly brain: {
125
- readonly kind: "caller";
126
- };
132
+ readonly brain: Extract<Brain, {
133
+ kind: "caller";
134
+ }>;
127
135
  readonly participants: readonly [ComputerUseParticipant];
128
136
  readonly subject: AppUrlSubject | {
129
137
  readonly kind: "local-app";