humanish 0.110.0 → 0.110.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 (132) hide show
  1. package/ARCHITECTURE.md +14 -11
  2. package/CHANGELOG.md +13 -0
  3. package/CONTEXT.md +8 -6
  4. package/README.md +96 -47
  5. package/dist/actors/computer-use/loop/ending.js +4 -4
  6. package/dist/actors/local-agent/claude-participant.d.ts +74 -0
  7. package/dist/actors/local-agent/claude-participant.js +243 -0
  8. package/dist/actors/local-agent/claude-session.d.ts +16 -3
  9. package/dist/actors/local-agent/claude-session.js +64 -23
  10. package/dist/actors/local-agent/cli.d.ts +11 -0
  11. package/dist/actors/local-agent/cli.js +103 -24
  12. package/dist/actors/local-agent/readiness.d.ts +2 -2
  13. package/dist/actors/local-agent/readiness.js +18 -11
  14. package/dist/cli/commands/analyze.js +21 -5
  15. package/dist/cli/commands/run-signals.d.ts +2 -0
  16. package/dist/cli/commands/run-signals.js +96 -44
  17. package/dist/cli/commands/runs.d.ts +5 -0
  18. package/dist/cli/commands/runs.js +86 -70
  19. package/dist/cli/commands/study-route-computer-use.js +2 -0
  20. package/dist/cli/commands/study-route-scripted.js +2 -0
  21. package/dist/cli/commands/study-route-shared-world.js +2 -0
  22. package/dist/cli/commands/study-route-terminal.js +2 -0
  23. package/dist/cli/doctor.d.ts +4 -1
  24. package/dist/cli/doctor.js +42 -4
  25. package/dist/cli/findings.d.ts +103 -0
  26. package/dist/cli/findings.js +316 -0
  27. package/dist/cli/first-run-path.d.ts +5 -4
  28. package/dist/cli/first-run-path.js +14 -7
  29. package/dist/cli/io.js +2 -1
  30. package/dist/cli/product-sentence.d.ts +3 -3
  31. package/dist/cli/product-sentence.js +3 -3
  32. package/dist/keys/env-file.d.ts +4 -0
  33. package/dist/keys/env-file.js +17 -0
  34. package/dist/observer/data.d.ts +14 -1
  35. package/dist/observer/data.js +19 -9
  36. package/dist/observer/library.d.ts +4 -0
  37. package/dist/observer/library.js +18 -15
  38. package/dist/observer/render.js +8 -2
  39. package/dist/observer/run-routes.d.ts +2 -0
  40. package/dist/observer/run-routes.js +43 -34
  41. package/dist/observer-app.html +3 -3
  42. package/dist/routes/computer-use/bundle.js +3 -1
  43. package/dist/routes/computer-use/fanout-records.js +1 -1
  44. package/dist/routes/computer-use/participant-execution.js +3 -1
  45. package/dist/routes/computer-use/participant-model.js +5 -2
  46. package/dist/routes/computer-use/plan.js +4 -4
  47. package/dist/routes/computer-use/preflight.js +1 -1
  48. package/dist/routes/computer-use/result.js +17 -28
  49. package/dist/routes/computer-use/single-bundle.js +7 -1
  50. package/dist/routes/scripted/bundle.js +4 -2
  51. package/dist/routes/scripted/plan.js +2 -2
  52. package/dist/routes/scripted/result.d.ts +3 -5
  53. package/dist/routes/scripted/result.js +16 -22
  54. package/dist/routes/scripted/scenario.js +4 -4
  55. package/dist/routes/shared-world/bundle-records.js +6 -1
  56. package/dist/routes/shared-world/bundle.js +2 -0
  57. package/dist/routes/shared-world/plan.js +1 -1
  58. package/dist/routes/shared-world/result.js +22 -22
  59. package/dist/routes/terminal/bundle.js +4 -2
  60. package/dist/routes/terminal/dry-run.js +8 -12
  61. package/dist/routes/terminal/ledger.d.ts +3 -3
  62. package/dist/routes/terminal/ledger.js +6 -6
  63. package/dist/routes/terminal/live-finish.js +15 -13
  64. package/dist/routes/terminal/plan.js +4 -4
  65. package/dist/routes/terminal/result.d.ts +6 -7
  66. package/dist/routes/terminal/result.js +6 -22
  67. package/dist/routes/terminal/session.js +1 -1
  68. package/dist/run/bundle-shape.d.ts +3 -1
  69. package/dist/run/bundle-shape.js +25 -1
  70. package/dist/run/bundle.d.ts +24 -0
  71. package/dist/run/display.d.ts +59 -0
  72. package/dist/run/display.js +106 -0
  73. package/dist/run/dry-run.js +11 -7
  74. package/dist/run/judge.d.ts +3 -2
  75. package/dist/run/judge.js +10 -0
  76. package/dist/run/pricing.js +1 -1
  77. package/dist/run/projection.d.ts +0 -2
  78. package/dist/run/projection.js +0 -11
  79. package/dist/run/reclaim-outcomes.d.ts +89 -0
  80. package/dist/run/reclaim-outcomes.js +213 -0
  81. package/dist/run/reclaim.d.ts +18 -17
  82. package/dist/run/reclaim.js +180 -113
  83. package/dist/run/results.d.ts +10 -20
  84. package/dist/run/results.js +2 -2
  85. package/dist/run/run-index.d.ts +11 -1
  86. package/dist/run/run-index.js +11 -0
  87. package/dist/run/run.d.ts +34 -18
  88. package/dist/run/run.js +166 -67
  89. package/dist/run/sandbox-creates.d.ts +59 -0
  90. package/dist/run/sandbox-creates.js +138 -0
  91. package/dist/run/sandbox-receipts.d.ts +14 -0
  92. package/dist/run/sandbox-receipts.js +44 -0
  93. package/dist/run/stats.d.ts +5 -0
  94. package/dist/run/stats.js +8 -4
  95. package/dist/run/status.d.ts +6 -9
  96. package/dist/run/status.js +7 -23
  97. package/dist/run/stored-runs.d.ts +5 -14
  98. package/dist/run/stored-runs.js +31 -146
  99. package/dist/run/streams.d.ts +3 -2
  100. package/dist/study/doctor.d.ts +1 -1
  101. package/dist/study/doctor.js +5 -2
  102. package/dist/study/init.js +14 -3
  103. package/dist/study/keys.d.ts +12 -0
  104. package/dist/study/keys.js +32 -0
  105. package/dist/study/persona.d.ts +4 -0
  106. package/dist/study/persona.js +4 -2
  107. package/dist/substrates/e2b/peer-install.d.ts +51 -0
  108. package/dist/substrates/e2b/peer-install.js +161 -0
  109. package/dist/substrates/e2b/sandbox.d.ts +34 -6
  110. package/dist/substrates/e2b/sandbox.js +128 -35
  111. package/dist/substrates/e2b/sdk.d.ts +33 -0
  112. package/dist/substrates/e2b/sdk.js +21 -21
  113. package/dist/substrates/shell.d.ts +2 -0
  114. package/dist/substrates/shell.js +4 -0
  115. package/dist/tui-app.js +133 -133
  116. package/dist/verify/liveness.d.ts +19 -3
  117. package/dist/verify/liveness.js +46 -25
  118. package/dist/verify/verify.d.ts +3 -0
  119. package/dist/verify/verify.js +6 -2
  120. package/docs/architecture/actor-contract.md +2 -1
  121. package/docs/architecture/observer.md +22 -7
  122. package/docs/architecture/task-protocol-support.md +13 -13
  123. package/docs/architecture/terminal-product-route.md +1 -1
  124. package/docs/contracts/run-bundle.md +75 -6
  125. package/docs/contracts/schemas.md +39 -22
  126. package/docs/contracts/study-analysis.md +45 -0
  127. package/docs/contracts/study-costs.md +8 -0
  128. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +3 -0
  129. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +9 -3
  130. package/docs/principles/invariants-and-defaults.md +11 -8
  131. package/package.json +4 -3
  132. package/skills/humanish/SKILL.md +16 -2
@@ -11,7 +11,8 @@ import { projectShareCheckedAnalysis } from "../analysis/sharing.js";
11
11
  import { loadAnalysis } from "../analysis/load.js";
12
12
  import { physicalCwdOf, runIdOf, bindExistingRunArtifactPaths, isSafeRunIdSegment, resolveLatestRunDirectory, validatePreparedRunArtifactPaths, } from "../run/paths.js";
13
13
  import { writeContainedOutputFile } from "../run/contained-output.js";
14
- import { loadRunBundlePrepared } from "../run/locate.js";
14
+ import { loadRunBundlePrepared, readRunJsonIfExists } from "../run/locate.js";
15
+ import { RUN_STATUS_FILE } from "../run/status.js";
15
16
  import { verifyRunPrepared } from "../verify/verify.js";
16
17
  import { renderObserverHtml } from "./artifact.js";
17
18
  import { buildObserverData } from "./data.js";
@@ -99,7 +100,12 @@ export async function renderObserver(cwdInput, runInput, options = {}) {
99
100
  ...projectShareCheckedAnalysis(await loadAnalysis(preparedRunPaths)),
100
101
  ...(spend === null ? {} : { spend }),
101
102
  };
102
- const observerData = buildObserverData(loaded.bundle);
103
+ // A run.json without an outcome is in progress, interrupted, or older than the field: its
104
+ // status.json says which, and holds an older run's ok.
105
+ const statusRecord = loaded.bundle.outcome === undefined
106
+ ? await readRunJsonIfExists(preparedRunPaths, RUN_STATUS_FILE)
107
+ : undefined;
108
+ const observerData = buildObserverData(loaded.bundle, undefined, statusRecord);
103
109
  observerData.publicSafety.share = {
104
110
  status: verified.shareSafety.status,
105
111
  verifiedAt: new Date().toISOString(),
@@ -1,4 +1,5 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { RunDisplay } from "../run/display.js";
2
3
  import { type ObserverData } from "./data.js";
3
4
  import { type PinnedDirectory } from "./pinned-files.js";
4
5
  export interface ObserverRuntimeStreamUrl {
@@ -22,6 +23,7 @@ export declare function buildHistoryIndex(proofRoot: PinnedDirectory, admitRun?:
22
23
  mode: string | null;
23
24
  href: string;
24
25
  status: string;
26
+ display?: RunDisplay;
25
27
  runtimeState?: NonNullable<ObserverData["runtime"]>["state"];
26
28
  streamCount: number;
27
29
  estimatedCostUsd: number | null;
@@ -8,7 +8,7 @@ import { listRuns } from "../run/stored-runs.js";
8
8
  import { readAnalysisAccounting } from "../run/costs.js";
9
9
  import { bindExistingRunArtifactPaths, isPathInside, isSafeRunIdSegment, } from "../run/paths.js";
10
10
  import { analysisCostOf, runCost, runCostLabel } from "../run/run-cost.js";
11
- import { RUN_STATUS_FILE, RUN_STATUS_STALE_MS, isRunStatusRecord } from "../run/status.js";
11
+ import { RUN_STATUS_FILE, RUN_STATUS_STALE_MS, isRunStatusRecord, } from "../run/status.js";
12
12
  import { renderObserverHtml } from "./artifact.js";
13
13
  import { buildObserverData, recordedStreamEmbed, withObserverEndings, } from "./data.js";
14
14
  import { buildArtifactSecurityHeaders } from "./http.js";
@@ -120,6 +120,7 @@ export async function serveRunPath(runRoot, relativePath, response, runtimeStrea
120
120
  }
121
121
  }
122
122
  async function readObserverData(runRoot, runtimeStreamUrls = []) {
123
+ const record = await readLocalRunStatus(runRoot);
123
124
  // Best-effort load from either source. Both reads swallow all errors on
124
125
  // purpose: this runs on every browser poll of a live run, where run.json may
125
126
  // be absent, still being written (a partial-JSON parse error), or superseded
@@ -130,57 +131,64 @@ async function readObserverData(runRoot, runtimeStreamUrls = []) {
130
131
  if (!bundleBytes)
131
132
  throw new Error("run.json unavailable");
132
133
  const bundle = JSON.parse(bundleBytes.toString("utf8"));
133
- return withRuntimeStreamUrls(await withLocalRunStatus(runRoot, buildObserverData(bundle)), runtimeStreamUrls);
134
+ return withRuntimeStreamUrls(withLocalRunStatus(record, buildObserverData(bundle, undefined, record)), runtimeStreamUrls);
134
135
  }
135
136
  catch { }
136
137
  try {
137
138
  const observerBytes = await readContainedFile(runRoot, path.join(runRoot.physicalPath, "observer", "observer-data.json"));
138
139
  if (!observerBytes)
139
140
  throw new Error("observer-data.json unavailable");
140
- return withRuntimeStreamUrls(await withLocalRunStatus(runRoot, withObserverEndings(JSON.parse(observerBytes.toString("utf8")))), runtimeStreamUrls);
141
+ return withRuntimeStreamUrls(withLocalRunStatus(record, withObserverEndings(JSON.parse(observerBytes.toString("utf8")))), runtimeStreamUrls);
141
142
  }
142
143
  catch { }
143
144
  return null;
144
145
  }
145
- /**
146
- * Liveness is a current read of a contained local status record, separate from run evidence.
147
- * A stale heartbeat means unknown: neither an old timestamp nor a persisted PID proves that a
148
- * process died (the evidence may have been copied from another machine). No PID is served/probed.
149
- */
150
- async function withLocalRunStatus(runRoot, input) {
151
- // A served observation must never be inherited from a persisted projection or export.
152
- const { runtime: _persistedRuntime, ...data } = input;
146
+ /** The run directory's own status record, when it is well formed and names that directory. */
147
+ async function readLocalRunStatus(runRoot) {
153
148
  try {
154
149
  const bytes = await readContainedFile(runRoot, path.join(runRoot.physicalPath, RUN_STATUS_FILE));
155
150
  if (!bytes)
156
- return data;
151
+ return undefined;
157
152
  const record = JSON.parse(bytes.toString("utf8"));
158
- if (!isRunStatusRecord(record) ||
159
- record.runId !== data.run.runId ||
160
- record.mode !== data.run.mode ||
161
- record.runId !== path.basename(runRoot.physicalPath))
162
- return data;
163
- const now = Date.now();
164
- const started = Date.parse(record.startedAt);
165
- const updated = Date.parse(record.updatedAt);
166
- const timestampsValid = Number.isFinite(started) && Number.isFinite(updated) && started <= updated && updated <= now;
167
- let state = "unknown";
168
- if (timestampsValid) {
169
- if (record.state === "finished") {
170
- state = "finished";
171
- }
172
- else if (record.state === "running" && now - updated <= RUN_STATUS_STALE_MS) {
173
- state = "running";
174
- }
175
- }
176
- return {
177
- ...data,
178
- runtime: { state, observedAt: new Date(now).toISOString(), source: "local-run-status" },
179
- };
153
+ return isRunStatusRecord(record) && record.runId === path.basename(runRoot.physicalPath)
154
+ ? record
155
+ : undefined;
180
156
  }
181
157
  catch {
158
+ return undefined;
159
+ }
160
+ }
161
+ /**
162
+ * Liveness is a current read of a contained local status record, separate from run evidence.
163
+ * A stale heartbeat means unknown: neither an old timestamp nor a persisted PID proves that a
164
+ * process died (the evidence may have been copied from another machine). A record its stopped
165
+ * process wrote is interrupted. No PID is served/probed.
166
+ */
167
+ function withLocalRunStatus(record, input) {
168
+ // A served observation must never be inherited from a persisted projection or export.
169
+ const { runtime: _persistedRuntime, ...data } = input;
170
+ if (record === undefined || record.runId !== data.run.runId || record.mode !== data.run.mode)
182
171
  return data;
172
+ const now = Date.now();
173
+ const started = Date.parse(record.startedAt);
174
+ const updated = Date.parse(record.updatedAt);
175
+ const timestampsValid = Number.isFinite(started) && Number.isFinite(updated) && started <= updated && updated <= now;
176
+ let state = "unknown";
177
+ if (timestampsValid) {
178
+ if (record.state === "finished") {
179
+ state = "finished";
180
+ }
181
+ else if (record.state === "interrupted") {
182
+ state = "interrupted";
183
+ }
184
+ else if (record.state === "running" && now - updated <= RUN_STATUS_STALE_MS) {
185
+ state = "running";
186
+ }
183
187
  }
188
+ return {
189
+ ...data,
190
+ runtime: { state, observedAt: new Date(now).toISOString(), source: "local-run-status" },
191
+ };
184
192
  }
185
193
  /** internal: exported for the stream lifecycle tests. */
186
194
  export function withRuntimeStreamUrls(data, runtimeStreamUrls) {
@@ -249,6 +257,7 @@ admitRun) {
249
257
  mode: admitRun ? (data?.run.mode ?? null) : run.mode,
250
258
  href: `/_humanish/runs/${encodeURIComponent(run.runId)}/observer/index.html`,
251
259
  status: data?.run.status ?? "unknown",
260
+ ...(data?.run.display === undefined ? {} : { display: data.run.display }),
252
261
  ...(data?.runtime ? { runtimeState: data.runtime.state } : {}),
253
262
  streamCount: data?.streams.length ?? 0,
254
263
  // Labeled run-total cost estimate (advisory; null when the run carries no cost summary).