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.
- package/AGENTS.md +3 -1
- package/CHANGELOG.md +10 -0
- package/CONTRIBUTING.md +4 -2
- package/dist/actors/codex/qualified-versions.d.ts +1 -1
- package/dist/actors/codex/qualified-versions.js +1 -1
- package/dist/actors/contract.d.ts +1 -1
- package/dist/actors/contract.js +7 -1
- package/dist/lab/composition-rules.d.ts +2 -0
- package/dist/lab/composition-rules.js +15 -6
- package/dist/lab/plan-base.d.ts +6 -0
- package/dist/lab/plan-base.js +16 -3
- package/dist/lab/plan-types.d.ts +12 -4
- package/dist/observer-app.html +1 -1
- package/dist/routes/computer-use/participant-model.js +10 -9
- package/dist/routes/computer-use/plan.js +7 -5
- package/dist/routes/computer-use/preflight.d.ts +3 -6
- package/dist/routes/computer-use/preflight.js +11 -7
- package/dist/routes/computer-use/route.d.ts +3 -3
- package/dist/routes/computer-use/route.js +3 -3
- package/dist/routes/computer-use/run-lanes.js +3 -3
- package/dist/routes/computer-use/setup.d.ts +0 -3
- package/dist/routes/computer-use/setup.js +3 -15
- package/dist/routes/computer-use/types.d.ts +3 -4
- package/dist/routes/computer-use/types.js +0 -1
- package/dist/routes/scripted/subject.js +2 -1
- package/dist/routes/shared-world/provisioned.js +2 -1
- package/dist/routes/shared-world/seats.js +3 -3
- package/dist/routes/terminal/live-sandbox.d.ts +1 -0
- package/dist/routes/terminal/live-sandbox.js +5 -1
- package/dist/routes/terminal/sandbox.d.ts +2 -0
- package/dist/routes/terminal/sandbox.js +4 -7
- package/dist/run/reclaim.d.ts +1 -1
- package/dist/run/reclaim.js +11 -1
- package/dist/substrates/desktop-session.d.ts +2 -0
- package/dist/substrates/e2b/sandbox.d.ts +2 -0
- package/dist/substrates/e2b/sandbox.js +21 -7
- package/dist/substrates/e2b/sdk.d.ts +12 -1
- package/dist/substrates/e2b/sdk.js +28 -7
- package/docs/architecture/restricted-codex-analysis.md +4 -2
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { redactText, toErrorMessage } from "../../evidence/redaction.js";
|
|
8
8
|
import { appendSandboxReceipt } from "../../run/sandbox-receipts.js";
|
|
9
9
|
import { ownDesktopAllocation, } from "../desktop-session.js";
|
|
10
|
-
import { E2BDesktopStartupError, isSandboxNotFoundError, } from "./sdk.js";
|
|
10
|
+
import { E2B_DEBUG_KILL_DETAIL, E2BDesktopStartupError, e2bDebugMode, isSandboxNotFoundError, } from "./sdk.js";
|
|
11
11
|
/** A desktop sandbox, on the stock `desktop` template or a named one. */
|
|
12
12
|
export function acquireE2BDesktopSandbox(request) {
|
|
13
13
|
return acquire(request, request.template);
|
|
@@ -56,13 +56,22 @@ function boundKill(module) {
|
|
|
56
56
|
* The SDK resolves false for an id it no longer knows (a 404), and a SandboxNotFoundError,
|
|
57
57
|
* recognized by type, means the same. Every other throw is unconfirmed, whatever its message
|
|
58
58
|
* says: the SDK answers a 404 with false before it throws, so "not found" or "404" in a thrown
|
|
59
|
-
* message comes from some other failure, such as a trace id.
|
|
59
|
+
* message comes from some other failure, such as a trace id. A true in debug mode sent no
|
|
60
|
+
* request, so it confirms nothing. Never list the account.
|
|
60
61
|
*/
|
|
61
62
|
async function killById(kill, sandboxId, options) {
|
|
62
63
|
if (kill === undefined)
|
|
63
64
|
return { status: "unconfirmed", reason: "release_unavailable" };
|
|
65
|
+
// The SDK reads the variable when the call starts, so read it at the same point.
|
|
66
|
+
const debug = e2bDebugMode();
|
|
64
67
|
try {
|
|
65
68
|
const result = await kill(sandboxId, options);
|
|
69
|
+
if (result === true && debug)
|
|
70
|
+
return {
|
|
71
|
+
status: "unconfirmed",
|
|
72
|
+
reason: "release_unavailable",
|
|
73
|
+
detail: E2B_DEBUG_KILL_DETAIL,
|
|
74
|
+
};
|
|
66
75
|
if (result === true)
|
|
67
76
|
return { status: "released", reason: "terminated" };
|
|
68
77
|
if (result === false)
|
|
@@ -105,7 +114,9 @@ export function readE2BRelease(result, options) {
|
|
|
105
114
|
case "release_unavailable":
|
|
106
115
|
return {
|
|
107
116
|
released: false,
|
|
108
|
-
warning:
|
|
117
|
+
warning: result.detail === undefined
|
|
118
|
+
? `Installed @e2b/desktop SDK does not expose Sandbox.kill; server-side kill-on-timeout will reclaim the ${label.toLowerCase()}.`
|
|
119
|
+
: `${label} release is unconfirmed: ${result.detail}. If it exists, server-side kill-on-timeout will reclaim it.`,
|
|
109
120
|
};
|
|
110
121
|
case "release_failed":
|
|
111
122
|
return {
|
|
@@ -119,6 +130,12 @@ export function readE2BRelease(result, options) {
|
|
|
119
130
|
};
|
|
120
131
|
}
|
|
121
132
|
}
|
|
133
|
+
/** A release_unavailable result as one lowercase line, for routes and reclaim that report it. */
|
|
134
|
+
export function releaseUnavailableDetail(detail) {
|
|
135
|
+
return detail === undefined
|
|
136
|
+
? "installed @e2b/desktop SDK does not expose Sandbox.kill; server-side kill-on-timeout will reclaim the sandbox"
|
|
137
|
+
: `${detail}; if the sandbox exists, server-side kill-on-timeout will reclaim it`;
|
|
138
|
+
}
|
|
122
139
|
/**
|
|
123
140
|
* Kill one sandbox by its exact recorded id, for reclaim, and map the shared release result onto
|
|
124
141
|
* reclaim's persisted outcome. It never lists the account.
|
|
@@ -129,10 +146,7 @@ export async function destroyE2BSandbox(module, sandboxId, options) {
|
|
|
129
146
|
return { state: released.reason === "terminated" ? "killed" : "already-gone" };
|
|
130
147
|
switch (released.reason) {
|
|
131
148
|
case "release_unavailable":
|
|
132
|
-
return {
|
|
133
|
-
state: "kill-failed",
|
|
134
|
-
detail: "installed @e2b/desktop SDK does not expose Sandbox.kill; server-side kill-on-timeout will reclaim the sandbox",
|
|
135
|
-
};
|
|
149
|
+
return { state: "kill-failed", detail: releaseUnavailableDetail(released.detail) };
|
|
136
150
|
case "invalid_result":
|
|
137
151
|
return {
|
|
138
152
|
state: "kill-failed",
|
|
@@ -165,7 +165,8 @@ type DesktopCreateCleanup = "killed" | "already_gone" | "unconfirmed";
|
|
|
165
165
|
/** Startup failed after this call acquired a handle. No credentials/options are included here. */
|
|
166
166
|
export declare class E2BDesktopStartupError extends Error {
|
|
167
167
|
readonly cleanup: DesktopCreateCleanup;
|
|
168
|
-
|
|
168
|
+
readonly cleanupDetail?: string | undefined;
|
|
169
|
+
constructor(error: unknown, cleanup: DesktopCreateCleanup, cleanupDetail?: string | undefined);
|
|
169
170
|
}
|
|
170
171
|
/**
|
|
171
172
|
* Preserve ownership before the desktop SDK starts Xvfb/XFCE (#581). Its public generic create
|
|
@@ -191,4 +192,14 @@ export declare function guardDesktopSandboxCreate(module: E2BDesktopModule): E2B
|
|
|
191
192
|
* that the exact sandbox humanish created is gone (confirmed reclaimed), never a re-list.
|
|
192
193
|
*/
|
|
193
194
|
export declare function isSandboxNotFoundError(error: unknown): boolean;
|
|
195
|
+
/** The variable that puts the E2B SDK in debug mode. */
|
|
196
|
+
export declare const E2B_DEBUG_ENV = "E2B_DEBUG";
|
|
197
|
+
/**
|
|
198
|
+
* Whether the E2B SDK runs in debug mode, read the way the SDK reads it when a call starts. In
|
|
199
|
+
* debug mode `Sandbox.kill` returns true without sending a request to E2B, so a true confirms
|
|
200
|
+
* nothing.
|
|
201
|
+
*/
|
|
202
|
+
export declare function e2bDebugMode(env?: NodeJS.ProcessEnv): boolean;
|
|
203
|
+
/** Why a kill that returned true in debug mode is unconfirmed. */
|
|
204
|
+
export declare const E2B_DEBUG_KILL_DETAIL = "E2B_DEBUG=true makes the E2B SDK return true from Sandbox.kill without contacting E2B";
|
|
194
205
|
export {};
|
|
@@ -29,15 +29,17 @@ export const DESKTOP_CREATE_CLEANUP_TIMEOUT_MS = 10_000;
|
|
|
29
29
|
/** Startup failed after this call acquired a handle. No credentials/options are included here. */
|
|
30
30
|
export class E2BDesktopStartupError extends Error {
|
|
31
31
|
cleanup;
|
|
32
|
-
|
|
32
|
+
cleanupDetail;
|
|
33
|
+
constructor(error, cleanup, cleanupDetail) {
|
|
33
34
|
const detail = error instanceof Error ? error.message : String(error);
|
|
34
35
|
const cleanupNote = cleanup === "killed"
|
|
35
36
|
? "the allocated sandbox was reclaimed"
|
|
36
37
|
: cleanup === "already_gone"
|
|
37
38
|
? "the allocated sandbox was already gone"
|
|
38
|
-
:
|
|
39
|
+
: `cleanup of the allocated sandbox was not confirmed${cleanupDetail === undefined ? "" : ` (${cleanupDetail})`}; no retry is allowed and its provider timeout remains the backstop`;
|
|
39
40
|
super(`Desktop startup failed after allocation; ${cleanupNote}. ${detail}`, { cause: error });
|
|
40
41
|
this.cleanup = cleanup;
|
|
42
|
+
this.cleanupDetail = cleanupDetail;
|
|
41
43
|
this.name = "E2BDesktopStartupError";
|
|
42
44
|
}
|
|
43
45
|
}
|
|
@@ -78,7 +80,7 @@ export function guardDesktopSandboxCreate(module) {
|
|
|
78
80
|
// SDK 2.4 calls this method before create rejects. Keep its boolean contract while
|
|
79
81
|
// recording unconfirmed cleanup independently of the SDK's catch-and-discard path.
|
|
80
82
|
this.kill = async () => {
|
|
81
|
-
const cleanup = await reclaim();
|
|
83
|
+
const { cleanup } = await reclaim();
|
|
82
84
|
if (cleanup === "unconfirmed")
|
|
83
85
|
throw new Error("Desktop startup cleanup was not confirmed");
|
|
84
86
|
return cleanup === "killed";
|
|
@@ -103,8 +105,8 @@ export function guardDesktopSandboxCreate(module) {
|
|
|
103
105
|
catch (error) {
|
|
104
106
|
if (cleanupOwned === undefined)
|
|
105
107
|
throw error;
|
|
106
|
-
const cleanup = await cleanupOwned();
|
|
107
|
-
throw new E2BDesktopStartupError(error, cleanup);
|
|
108
|
+
const { cleanup, detail } = await cleanupOwned();
|
|
109
|
+
throw new E2BDesktopStartupError(error, cleanup, detail);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
}
|
|
@@ -113,6 +115,8 @@ export function guardDesktopSandboxCreate(module) {
|
|
|
113
115
|
async function reclaimFailedDesktopCreate(kill, timeoutMs) {
|
|
114
116
|
const controller = new AbortController();
|
|
115
117
|
let timer;
|
|
118
|
+
// The SDK reads the variable when the call starts, so read it at the same point.
|
|
119
|
+
const debug = e2bDebugMode();
|
|
116
120
|
try {
|
|
117
121
|
const result = await Promise.race([
|
|
118
122
|
kill({ requestTimeoutMs: timeoutMs, signal: controller.signal }),
|
|
@@ -123,12 +127,17 @@ async function reclaimFailedDesktopCreate(kill, timeoutMs) {
|
|
|
123
127
|
}, timeoutMs);
|
|
124
128
|
}),
|
|
125
129
|
]);
|
|
130
|
+
// A true in debug mode sent no request, so it confirms nothing.
|
|
131
|
+
if (result === true && debug)
|
|
132
|
+
return { cleanup: "unconfirmed", detail: E2B_DEBUG_KILL_DETAIL };
|
|
126
133
|
// The installed SDK documents false as an exact-id 404: already absent is also reclaimed.
|
|
127
|
-
|
|
134
|
+
if (result === true)
|
|
135
|
+
return { cleanup: "killed" };
|
|
136
|
+
return { cleanup: result === false ? "already_gone" : "unconfirmed" };
|
|
128
137
|
}
|
|
129
138
|
catch {
|
|
130
139
|
// Do not serialize cleanup options, connection state, or provider errors that may echo auth.
|
|
131
|
-
return "unconfirmed";
|
|
140
|
+
return { cleanup: "unconfirmed" };
|
|
132
141
|
}
|
|
133
142
|
finally {
|
|
134
143
|
if (timer !== undefined)
|
|
@@ -166,3 +175,15 @@ export function isSandboxNotFoundError(error) {
|
|
|
166
175
|
const value = error;
|
|
167
176
|
return (value.name === "SandboxNotFoundError" || value.constructor?.name === "SandboxNotFoundError");
|
|
168
177
|
}
|
|
178
|
+
/** The variable that puts the E2B SDK in debug mode. */
|
|
179
|
+
export const E2B_DEBUG_ENV = "E2B_DEBUG";
|
|
180
|
+
/**
|
|
181
|
+
* Whether the E2B SDK runs in debug mode, read the way the SDK reads it when a call starts. In
|
|
182
|
+
* debug mode `Sandbox.kill` returns true without sending a request to E2B, so a true confirms
|
|
183
|
+
* nothing.
|
|
184
|
+
*/
|
|
185
|
+
export function e2bDebugMode(env = process.env) {
|
|
186
|
+
return env[E2B_DEBUG_ENV]?.toLowerCase() === "true";
|
|
187
|
+
}
|
|
188
|
+
/** Why a kill that returned true in debug mode is unconfirmed. */
|
|
189
|
+
export const E2B_DEBUG_KILL_DETAIL = `${E2B_DEBUG_ENV}=true makes the E2B SDK return true from Sandbox.kill without contacting E2B`;
|
|
@@ -13,8 +13,10 @@ Linux x64 accepts 0.154.0, 0.157.1
|
|
|
13
13
|
([receipt](https://github.com/danielgwilson/humanish/blob/main/docs/goals/computer-use-actor/receipts/codex-cli-0.157.1-requalification-2026-09-30.md))
|
|
14
14
|
0.159.2
|
|
15
15
|
([receipt](https://github.com/danielgwilson/humanish/blob/main/docs/goals/computer-use-actor/receipts/codex-cli-0.159.2-qualification-2026-09-30.md))
|
|
16
|
-
|
|
17
|
-
([receipt](https://github.com/danielgwilson/humanish/blob/main/docs/goals/computer-use-actor/receipts/codex-cli-0.159.3-qualification-2026-10-01.md))
|
|
16
|
+
0.159.3
|
|
17
|
+
([receipt](https://github.com/danielgwilson/humanish/blob/main/docs/goals/computer-use-actor/receipts/codex-cli-0.159.3-qualification-2026-10-01.md))
|
|
18
|
+
and 0.160.0
|
|
19
|
+
([receipt](https://github.com/danielgwilson/humanish/blob/main/docs/goals/computer-use-actor/receipts/codex-cli-0.160.0-qualification-2026-10-01.md)).
|
|
18
20
|
Apple Silicon accepts 0.154.0, which passed installed participant/analysis studies and the
|
|
19
21
|
native dispatch restriction check on an M5 Max; later releases need the same check on a Mac.
|
|
20
22
|
Hosted participants on Linux arm64 and Intel macOS keep 0.154.0 as a pre-existing admission,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "humanish",
|
|
3
|
-
"version": "0.106.
|
|
3
|
+
"version": "0.106.1",
|
|
4
4
|
"description": "Open-source-safe CLI for persona simulation, observer review, and public-safe feedback drafts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-harness",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"format:check": "oxfmt --check",
|
|
93
93
|
"lint": "node scripts/check-lint-cap.mjs --max-warnings=444",
|
|
94
94
|
"knip": "knip",
|
|
95
|
-
"prose:check": "node scripts/check-code-prose.mjs --max-issue-refs=371 --max-fix-tags=23 --max-caps=
|
|
95
|
+
"prose:check": "node scripts/check-code-prose.mjs --max-issue-refs=371 --max-fix-tags=23 --max-caps=1742",
|
|
96
96
|
"vocabulary:check": "tsx scripts/check-retired-words.ts --max-lane=188 --max-seat=6 --max-role=52 --max-sim=51 --max-study=287"
|
|
97
97
|
},
|
|
98
98
|
"dependencies": {
|