humanish 0.35.0 → 0.36.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.
- package/dist/concurrent-shared-world-lab.js +23 -0
- package/dist/concurrent-shared-world-lab.js.map +1 -1
- package/dist/cua-actor-lab.d.ts +21 -0
- package/dist/cua-actor-lab.js +72 -14
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/e2b-terminal-lab.js +3 -0
- package/dist/e2b-terminal-lab.js.map +1 -1
- package/dist/observer-assets.js +36 -2
- package/dist/observer-assets.js.map +1 -1
- package/dist/observer.d.ts +7 -0
- package/dist/observer.js +13 -6
- package/dist/observer.js.map +1 -1
- package/dist/program.js +28 -0
- package/dist/program.js.map +1 -1
- package/dist/reclaim.d.ts +31 -0
- package/dist/reclaim.js +90 -0
- package/dist/reclaim.js.map +1 -0
- package/dist/run.d.ts +3 -0
- package/dist/run.js +3 -1
- package/dist/run.js.map +1 -1
- package/dist/sandbox-receipts.d.ts +19 -0
- package/dist/sandbox-receipts.js +51 -0
- package/dist/sandbox-receipts.js.map +1 -0
- package/dist/shared-world-lab.js +3 -0
- package/dist/shared-world-lab.js.map +1 -1
- package/docs/contracts/schemas.md +1 -1
- package/docs/goals/current.md +1 -1
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
package/dist/reclaim.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// `humanish reclaim` (#358 salvage tier): kill an interrupted run's sandboxes by the EXACT ids the
|
|
2
|
+
// run journaled at create time (sandbox-receipts.ndjson), and say honestly what happened to each.
|
|
3
|
+
// The lane loop lives in the operator's local process, so a sleeping laptop or a crash orphans
|
|
4
|
+
// every sandbox with the ids trapped in dead memory; before this command the only remedies were
|
|
5
|
+
// the server-side create-time TTL (slow, spend keeps burning) or account enumeration (which this
|
|
6
|
+
// codebase never does — an account-wide operation once destroyed unrelated infrastructure). This
|
|
7
|
+
// reads one file inside the managed run dir, kills by id, and never lists anything.
|
|
8
|
+
import { loadE2BDesktopModule } from "./e2b-desktop-launch.js";
|
|
9
|
+
import { readContainedRegularFile, writeContainedOutputFile } from "./selected-output-paths.js";
|
|
10
|
+
import { resolveRunPath } from "./run.js";
|
|
11
|
+
import { parseSandboxReceipts, SANDBOX_RECEIPTS_ARTIFACT } from "./sandbox-receipts.js";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { toErrorMessage } from "./command-failure.js";
|
|
14
|
+
import { redactText } from "./redaction.js";
|
|
15
|
+
export const RECLAIM_RESULT_SCHEMA = "humanish.reclaim-result.v1";
|
|
16
|
+
export const RECLAIM_RECEIPT_ARTIFACT = "reclaim-receipt.json";
|
|
17
|
+
export async function reclaimRunSandboxes(cwd, runInput, hooks = {}) {
|
|
18
|
+
const warnings = [];
|
|
19
|
+
const base = { schema: RECLAIM_RESULT_SCHEMA, cwd, runId: runInput, receiptCount: 0, outcomes: [], warnings };
|
|
20
|
+
const runPaths = await resolveRunPath(cwd, runInput);
|
|
21
|
+
if (!runPaths) {
|
|
22
|
+
return {
|
|
23
|
+
...base,
|
|
24
|
+
ok: false,
|
|
25
|
+
error: { code: "HUMANISH_RECLAIM_RUN_NOT_FOUND", message: `No run found for "${runInput}" (use \`humanish runs\` to list runs).` }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const runId = path.basename(runPaths.absoluteRunRoot);
|
|
29
|
+
const bytes = await readContainedRegularFile(runPaths, SANDBOX_RECEIPTS_ARTIFACT);
|
|
30
|
+
if (bytes === null) {
|
|
31
|
+
// Honest empty: nothing journaled means either no sandbox was ever created (cheap interrupt —
|
|
32
|
+
// nothing to reclaim) or the run predates receipts (0.35.x and earlier — the create-time TTL
|
|
33
|
+
// is the only backstop for those). Either way there is no id to act on, and saying so beats
|
|
34
|
+
// pretending a scan happened.
|
|
35
|
+
warnings.push("No sandbox-receipts.ndjson in this run dir: either no sandbox was created before the interrupt, or the run predates create-time receipts. Nothing to reclaim by id; server-side kill-on-timeout covers anything that did exist.");
|
|
36
|
+
return { ...base, runId, ok: true };
|
|
37
|
+
}
|
|
38
|
+
const receipts = parseSandboxReceipts(bytes.toString("utf8"));
|
|
39
|
+
let sandboxModule;
|
|
40
|
+
try {
|
|
41
|
+
sandboxModule = await (hooks.loadModule ?? loadE2BDesktopModule)();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
...base,
|
|
46
|
+
runId,
|
|
47
|
+
receiptCount: receipts.length,
|
|
48
|
+
ok: false,
|
|
49
|
+
error: { code: "HUMANISH_RECLAIM_MODULE_UNAVAILABLE", message: `Cannot load @e2b/desktop to kill by id: ${redactText(toErrorMessage(error))}` }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const requestTimeoutMs = hooks.requestTimeoutMs ?? 60_000;
|
|
53
|
+
const kill = sandboxModule.Sandbox.kill;
|
|
54
|
+
const outcomes = [];
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
for (const receipt of receipts) {
|
|
57
|
+
if (seen.has(receipt.sandboxId))
|
|
58
|
+
continue; // one attempt per id, however many receipts raced
|
|
59
|
+
seen.add(receipt.sandboxId);
|
|
60
|
+
if (typeof kill !== "function") {
|
|
61
|
+
outcomes.push({ sandboxId: receipt.sandboxId, laneId: receipt.laneId, state: "kill-failed", detail: "installed @e2b/desktop SDK does not expose Sandbox.kill; server-side kill-on-timeout will reclaim the sandbox" });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const killed = (await kill.call(sandboxModule.Sandbox, receipt.sandboxId, { requestTimeoutMs })) === true;
|
|
66
|
+
outcomes.push({ sandboxId: receipt.sandboxId, laneId: receipt.laneId, state: killed ? "killed" : "already-gone" });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const detail = redactText(toErrorMessage(error));
|
|
70
|
+
const gone = /not.?found|does not exist|404/i.test(detail);
|
|
71
|
+
outcomes.push({
|
|
72
|
+
sandboxId: receipt.sandboxId,
|
|
73
|
+
laneId: receipt.laneId,
|
|
74
|
+
state: gone ? "already-gone" : "kill-failed",
|
|
75
|
+
...(gone ? {} : { detail })
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const ok = outcomes.every((outcome) => outcome.state !== "kill-failed");
|
|
80
|
+
const result = { ...base, runId, receiptCount: receipts.length, outcomes, ok };
|
|
81
|
+
// Keep the reclaim record next to the run it cleaned: what was attempted, what happened, when.
|
|
82
|
+
try {
|
|
83
|
+
await writeContainedOutputFile(runPaths, RECLAIM_RECEIPT_ARTIFACT, `${JSON.stringify({ schema: RECLAIM_RESULT_SCHEMA, at: new Date().toISOString(), runId, receiptCount: receipts.length, outcomes }, null, 2)}\n`, "utf8");
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
warnings.push(`Reclaim ran but its receipt could not be written: ${redactText(toErrorMessage(error))}`);
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=reclaim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reclaim.js","sourceRoot":"","sources":["../src/reclaim.ts"],"names":[],"mappings":"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"}
|
package/dist/run.d.ts
CHANGED
|
@@ -970,4 +970,7 @@ export declare function readReview(cwdInput: string, runInput: string): Promise<
|
|
|
970
970
|
runId: string;
|
|
971
971
|
})>;
|
|
972
972
|
export declare function doctor(cwdInput: string): Promise<DoctorResult>;
|
|
973
|
+
/** Resolve "latest" or an explicit run id to its prepared artifact paths. Exported for the
|
|
974
|
+
* reclaim command (#358), which must locate a run WITHOUT trusting anything but the managed dir. */
|
|
975
|
+
export declare function resolveRunPath(cwd: string, runInput: string): Promise<PreparedRunArtifactPaths | null>;
|
|
973
976
|
export {};
|
package/dist/run.js
CHANGED
|
@@ -3147,7 +3147,9 @@ function parsePersonaYaml(text) {
|
|
|
3147
3147
|
function escapeRegExp(value) {
|
|
3148
3148
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3149
3149
|
}
|
|
3150
|
-
|
|
3150
|
+
/** Resolve "latest" or an explicit run id to its prepared artifact paths. Exported for the
|
|
3151
|
+
* reclaim command (#358), which must locate a run WITHOUT trusting anything but the managed dir. */
|
|
3152
|
+
export async function resolveRunPath(cwd, runInput) {
|
|
3151
3153
|
if (runInput === "latest") {
|
|
3152
3154
|
const runsRoot = await bindExistingManagedHumanishOutputDirectory(cwd, "runs");
|
|
3153
3155
|
if (!runsRoot) {
|