humanish 0.35.0 → 0.36.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 (38) hide show
  1. package/AGENTS.md +8 -0
  2. package/dist/concurrent-shared-world-lab.d.ts +1 -1
  3. package/dist/concurrent-shared-world-lab.js +26 -3
  4. package/dist/concurrent-shared-world-lab.js.map +1 -1
  5. package/dist/cua-actor-lab.d.ts +21 -0
  6. package/dist/cua-actor-lab.js +72 -14
  7. package/dist/cua-actor-lab.js.map +1 -1
  8. package/dist/e2b-terminal-lab.js +3 -0
  9. package/dist/e2b-terminal-lab.js.map +1 -1
  10. package/dist/init-templates.js +2 -2
  11. package/dist/init-templates.js.map +1 -1
  12. package/dist/lab-config.js +1 -1
  13. package/dist/lab-config.js.map +1 -1
  14. package/dist/observer-assets.js +36 -2
  15. package/dist/observer-assets.js.map +1 -1
  16. package/dist/observer.d.ts +7 -0
  17. package/dist/observer.js +13 -6
  18. package/dist/observer.js.map +1 -1
  19. package/dist/program.js +28 -0
  20. package/dist/program.js.map +1 -1
  21. package/dist/reclaim.d.ts +31 -0
  22. package/dist/reclaim.js +90 -0
  23. package/dist/reclaim.js.map +1 -0
  24. package/dist/run.d.ts +3 -0
  25. package/dist/run.js +3 -1
  26. package/dist/run.js.map +1 -1
  27. package/dist/sandbox-receipts.d.ts +19 -0
  28. package/dist/sandbox-receipts.js +51 -0
  29. package/dist/sandbox-receipts.js.map +1 -0
  30. package/dist/shared-world-lab.js +3 -0
  31. package/dist/shared-world-lab.js.map +1 -1
  32. package/docs/architecture/external-public-shared-world.md +3 -3
  33. package/docs/contracts/schemas.md +1 -1
  34. package/docs/goals/current.md +1 -1
  35. package/docs/product/{cineguessr-3player-external-public.md → lobby-trivia-3player-external-public.md} +4 -4
  36. package/docs/ramp/README.md +1 -1
  37. package/docs/release/0.20.0-external-public-shared-world.md +1 -1
  38. package/package.json +1 -1
@@ -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
- async function resolveRunPath(cwd, runInput) {
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) {