humanish 0.141.0 → 0.142.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/ARCHITECTURE.md +1 -0
- package/CHANGELOG.md +11 -0
- package/README.md +2 -0
- package/dist/analysis/admission.d.ts +8 -0
- package/dist/analysis/admission.js +15 -4
- package/dist/analysis/automatic-config.d.ts +5 -2
- package/dist/analysis/automatic-config.js +23 -8
- package/dist/analysis/automatic.js +13 -7
- package/dist/analysis/execute.d.ts +17 -6
- package/dist/analysis/execute.js +36 -18
- package/dist/analysis/gemini-wire.d.ts +8 -0
- package/dist/analysis/gemini-wire.js +165 -0
- package/dist/analysis/image-tokens.d.ts +4 -2
- package/dist/analysis/image-tokens.js +24 -3
- package/dist/analysis/job.d.ts +1 -0
- package/dist/analysis/job.js +1 -0
- package/dist/analysis/openai-wire.d.ts +5 -0
- package/dist/analysis/openai-wire.js +101 -0
- package/dist/analysis/provider.d.ts +15 -7
- package/dist/analysis/provider.js +21 -101
- package/dist/analysis/responses.d.ts +3 -0
- package/dist/analysis/responses.js +19 -0
- package/dist/analysis/service.js +11 -3
- package/dist/analysis/types.d.ts +8 -2
- package/dist/analysis/validation.d.ts +1 -0
- package/dist/analysis/validation.js +13 -12
- package/dist/cli/commands/analyze.js +9 -7
- package/dist/cli/commands/observe.js +26 -1
- package/dist/cli/commands/run-command.d.ts +1 -1
- package/dist/cli/commands/run-command.js +12 -0
- package/dist/cli/commands/study-remote.d.ts +13 -0
- package/dist/cli/commands/study-remote.js +125 -0
- package/dist/cli/commands/study-route-computer-use.js +26 -2
- package/dist/cli/commands/study-route-scripted.js +1 -0
- package/dist/cli/commands/study-route-shared-world.js +1 -0
- package/dist/cli/commands/study-route-terminal.js +1 -0
- package/dist/cli/commands/study-run.js +34 -0
- package/dist/cli/commands/watch.js +5 -0
- package/dist/cli/doctor.js +7 -2
- package/dist/cli/findings.d.ts +8 -1
- package/dist/cli/findings.js +38 -15
- package/dist/cli/io.d.ts +8 -0
- package/dist/cli/io.js +2 -1
- package/dist/keys/key-resolution.d.ts +10 -0
- package/dist/keys/key-resolution.js +33 -5
- package/dist/observer/listen.d.ts +7 -2
- package/dist/observer/listen.js +10 -4
- package/dist/observer/render.d.ts +2 -0
- package/dist/observer/render.js +1 -1
- package/dist/observer-app.html +1 -1
- package/dist/remote/launch.d.ts +53 -0
- package/dist/remote/launch.js +320 -0
- package/dist/remote/observer-proxy.d.ts +11 -0
- package/dist/remote/observer-proxy.js +66 -0
- package/dist/remote/plan.d.ts +35 -0
- package/dist/remote/plan.js +114 -0
- package/dist/remote/reattach.d.ts +17 -0
- package/dist/remote/reattach.js +81 -0
- package/dist/remote/runner.d.ts +68 -0
- package/dist/remote/runner.js +216 -0
- package/dist/routes/computer-use/e2b-desktop/start.js +1 -1
- package/dist/routes/computer-use/types.d.ts +2 -0
- package/dist/routes/scripted/types.d.ts +2 -0
- package/dist/routes/shared-world/types.d.ts +2 -0
- package/dist/routes/terminal/types.d.ts +2 -0
- package/dist/run/costs.d.ts +2 -1
- package/dist/run/pricing.d.ts +13 -1
- package/dist/run/pricing.js +50 -4
- package/dist/run/results.d.ts +1 -1
- package/dist/run/run-cost.d.ts +2 -1
- package/dist/run/run-cost.js +6 -1
- package/dist/run/run.d.ts +13 -0
- package/dist/run/run.js +18 -7
- package/dist/run/sandbox-creates.d.ts +10 -3
- package/dist/run/sandbox-creates.js +48 -6
- package/dist/run-study.d.ts +5 -0
- package/dist/study/doctor.js +14 -1
- package/dist/study/requirements.d.ts +1 -1
- package/dist/study/requirements.js +8 -6
- package/dist/study/route-inputs.js +4 -0
- package/dist/study/run-study-events.d.ts +1 -1
- package/dist/study/run-study-events.js +9 -2
- package/dist/substrates/e2b/base-module.d.ts +3 -0
- package/dist/substrates/e2b/base-module.js +40 -0
- package/dist/substrates/e2b/desktop-browser.d.ts +1 -1
- package/dist/substrates/e2b/desktop-browser.js +24 -6
- package/dist/substrates/e2b/sdk.d.ts +24 -0
- package/dist/substrates/e2b/sdk.js +5 -1
- package/dist/substrates/e2b/shell-only.d.ts +5 -0
- package/dist/substrates/e2b/shell-only.js +27 -0
- package/dist/substrates/modal/sandbox.js +27 -28
- package/dist/substrates/modal/sdk.d.ts +7 -0
- package/dist/tui-app.js +46 -46
- package/docs/contracts/study-analysis.md +51 -3
- package/docs/product/automatic-analysis.md +26 -2
- package/package.json +2 -2
- package/skills/humanish/SKILL.md +10 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// GH_TOKEN <- `gh auth token` (the gh CLI's credential chain);
|
|
12
12
|
// 4. the humanish user-level store `$XDG_CONFIG_HOME/humanish/keys.env`, written only by
|
|
13
13
|
// `humanish keys set` (0600, prompted or --stdin), the fallback for vendors that ship
|
|
14
|
-
// no machine chain of their own (OpenAI, Anthropic).
|
|
14
|
+
// no machine chain of their own (OpenAI, Anthropic, Gemini).
|
|
15
15
|
//
|
|
16
16
|
// Every fill is announced by key name + source, never by value. The subject app's own
|
|
17
17
|
// `.env`/`.env.local` are never read: those hold product credentials, a different class
|
|
@@ -34,7 +34,8 @@ import { OPENAI_EGRESS_PLACEHOLDER } from "../routes/terminal/runtime-auth.js";
|
|
|
34
34
|
* full-file load). ANTHROPIC_API_KEY is not listed, and doctor does not report it: a Claude Code
|
|
35
35
|
* participant runs on its own login and never receives it. CODEX_API_KEY is an alternative spelling
|
|
36
36
|
* of the OpenAI key for terminal studies. Doctor reports AGENTMAIL_API_KEY only under `--study`, for
|
|
37
|
-
* a study whose email connection names it, since a connection may name another variable
|
|
37
|
+
* a study whose email connection names it, since a connection may name another variable, and
|
|
38
|
+
* GEMINI_API_KEY only for a study whose analysis runs on Gemini.
|
|
38
39
|
*/
|
|
39
40
|
const PROVIDER_KEYS = [
|
|
40
41
|
{
|
|
@@ -69,9 +70,33 @@ const PROVIDER_KEYS = [
|
|
|
69
70
|
{ name: "GITHUB_TOKEN", spellingOf: "GH_TOKEN" },
|
|
70
71
|
{ name: "CODEX_API_KEY", doctor: true },
|
|
71
72
|
{ name: "AGENTMAIL_API_KEY", vendor: "agentmail", listed: { order: 4, use: "email in studies" } },
|
|
73
|
+
{ name: "GEMINI_API_KEY", vendor: "gemini", listed: { order: 5, use: "analysis on Gemini" } },
|
|
74
|
+
// Google's client libraries also read GOOGLE_API_KEY, and prefer it when both are set. humanish
|
|
75
|
+
// reads GEMINI_API_KEY first: a GOOGLE_API_KEY exported for Maps or Firebase must not take the
|
|
76
|
+
// place of the key `humanish keys set gemini` stored.
|
|
77
|
+
{ name: "GOOGLE_API_KEY", spellingOf: "GEMINI_API_KEY" },
|
|
72
78
|
];
|
|
73
79
|
const PROVIDER_KEY_SET = new Set(PROVIDER_KEYS.map((key) => key.name));
|
|
74
80
|
const providerKey = (name) => PROVIDER_KEYS.find((key) => key.name === name);
|
|
81
|
+
/**
|
|
82
|
+
* Every env name of the key `name` is a spelling of, in the order humanish reads them: the key's
|
|
83
|
+
* own name, then its second spellings. Discovery treats them as one key.
|
|
84
|
+
*/
|
|
85
|
+
function keyNames(name) {
|
|
86
|
+
const own = providerKey(name)?.spellingOf ?? name;
|
|
87
|
+
return [own, ...PROVIDER_KEYS.filter((key) => key.spellingOf === own).map((key) => key.name)];
|
|
88
|
+
}
|
|
89
|
+
/** The key each API analyst reads, under its first spelling. */
|
|
90
|
+
const ANALYSIS_KEYS = { openai: "OPENAI_API_KEY", gemini: "GEMINI_API_KEY" };
|
|
91
|
+
/** The env names an API analyst's key may have, in the order they are read. */
|
|
92
|
+
export const analysisKeyNames = (vendor) => keyNames(ANALYSIS_KEYS[vendor]);
|
|
93
|
+
/** An API analyst's key from `env`: the first of its names with a non-blank value, else "". */
|
|
94
|
+
export function analysisApiKey(vendor, env) {
|
|
95
|
+
for (const name of analysisKeyNames(vendor))
|
|
96
|
+
if (env[name]?.trim())
|
|
97
|
+
return env[name];
|
|
98
|
+
return "";
|
|
99
|
+
}
|
|
75
100
|
/** The vendor aliases `humanish keys set` accepts. A raw ENV_NAME is also accepted. */
|
|
76
101
|
export const KEY_VENDORS = PROVIDER_KEYS.flatMap((key) => key.vendor === undefined ? [] : [key.vendor]);
|
|
77
102
|
/** The keys `humanish keys` lists, in its order, each with what humanish uses it for. */
|
|
@@ -212,8 +237,11 @@ export async function discoverProviderKeys(args) {
|
|
|
212
237
|
const ignored = [];
|
|
213
238
|
// Fill-only means presence wins, including an explicitly-set empty value: an operator who
|
|
214
239
|
// exported OPENAI_API_KEY="" said "off", and a rung that "fixes" that has overridden them.
|
|
215
|
-
// Only a truly-unset name is fillable
|
|
216
|
-
|
|
240
|
+
// Only a truly-unset name is fillable, and only while no spelling of its key was set before
|
|
241
|
+
// discovery: a repo overlay's GOOGLE_API_KEY must not stand beside, and outrank, an exported
|
|
242
|
+
// GEMINI_API_KEY. Spellings that discovery itself fills may stand together.
|
|
243
|
+
const explicit = new Set(Object.keys(env).filter((name) => env[name] !== undefined));
|
|
244
|
+
const fillable = (name) => env[name] === undefined && keyNames(name).every((spelling) => !explicit.has(spelling));
|
|
217
245
|
const fill = (name, value, source) => {
|
|
218
246
|
env[name] = value;
|
|
219
247
|
fills.push({ name, source });
|
|
@@ -259,7 +287,7 @@ export async function discoverProviderKeys(args) {
|
|
|
259
287
|
// Rung 3c: the gh CLI's credential chain. Only consulted when neither GitHub env name is
|
|
260
288
|
// present; fills GH_TOKEN (the name humanish reads first). gh runs without any provider key in
|
|
261
289
|
// its environment, so the keys the rungs above just filled stay in this process.
|
|
262
|
-
if (
|
|
290
|
+
if (keyNames("GH_TOKEN").every((name) => env[name] === undefined)) {
|
|
263
291
|
const exec = deps.execText ?? defaultExecText;
|
|
264
292
|
const token = await exec("gh", ["auth", "token"], 3_000, withoutProviderKeys(env));
|
|
265
293
|
if (token !== null)
|
|
@@ -12,5 +12,10 @@ export declare class PortInUseError extends Error {
|
|
|
12
12
|
* that cannot decide says "other", which is the answer that suggests the safer action.
|
|
13
13
|
*/
|
|
14
14
|
export declare function probePortHolder(port: number, fetchFn?: typeof fetch): Promise<PortHolder>;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Bind on loopback; resolve the port that was actually bound; name a taken port. `allInterfaces`
|
|
17
|
+
* binds every interface instead, for the Observer of a remote run's runner sandbox: Modal's proxy
|
|
18
|
+
* cannot reach a loopback-only server, and only the provider's authenticated proxy reaches the
|
|
19
|
+
* sandbox's ports.
|
|
20
|
+
*/
|
|
21
|
+
export declare function listenOnLoopback(server: Server, port: number, probe?: (port: number) => Promise<PortHolder>, allInterfaces?: boolean): Promise<number>;
|
package/dist/observer/listen.js
CHANGED
|
@@ -61,8 +61,13 @@ async function probeRoutes(port, fetchFn) {
|
|
|
61
61
|
}
|
|
62
62
|
return "other";
|
|
63
63
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Bind on loopback; resolve the port that was actually bound; name a taken port. `allInterfaces`
|
|
66
|
+
* binds every interface instead, for the Observer of a remote run's runner sandbox: Modal's proxy
|
|
67
|
+
* cannot reach a loopback-only server, and only the provider's authenticated proxy reaches the
|
|
68
|
+
* sandbox's ports.
|
|
69
|
+
*/
|
|
70
|
+
export function listenOnLoopback(server, port, probe = probePortHolder, allInterfaces = false) {
|
|
66
71
|
return new Promise((resolve, reject) => {
|
|
67
72
|
const onError = (error) => {
|
|
68
73
|
if (error.code === "EADDRINUSE") {
|
|
@@ -72,8 +77,9 @@ export function listenOnLoopback(server, port, probe = probePortHolder) {
|
|
|
72
77
|
reject(error);
|
|
73
78
|
};
|
|
74
79
|
server.once("error", onError);
|
|
75
|
-
//
|
|
76
|
-
|
|
80
|
+
// Otherwise never beyond loopback; exposure only ever happens through a tunnel or proxy
|
|
81
|
+
// forwarding here.
|
|
82
|
+
server.listen(port, allInterfaces ? "0.0.0.0" : "127.0.0.1", () => {
|
|
77
83
|
server.off("error", onError);
|
|
78
84
|
const address = server.address();
|
|
79
85
|
if (!address || typeof address === "string") {
|
|
@@ -31,6 +31,8 @@ export interface ObserverServeOptions {
|
|
|
31
31
|
/** Restrict history and evidence routes to the selected run. Exposed viewers always do this. */
|
|
32
32
|
scope?: "run" | "library";
|
|
33
33
|
exposed?: boolean;
|
|
34
|
+
/** Bind every interface: only a remote run's runner sandbox, behind its provider's proxy. */
|
|
35
|
+
allInterfaces?: boolean;
|
|
34
36
|
}
|
|
35
37
|
export interface ObserverServer {
|
|
36
38
|
url: string;
|
package/dist/observer/render.js
CHANGED
|
@@ -293,7 +293,7 @@ export async function serveObserver(result, options = {}) {
|
|
|
293
293
|
const server = createServer((request, response) => {
|
|
294
294
|
void handleRequest(request, response);
|
|
295
295
|
});
|
|
296
|
-
port = await listenOnLoopback(server, options.port ?? 0);
|
|
296
|
+
port = await listenOnLoopback(server, options.port ?? 0, undefined, options.allInterfaces === true);
|
|
297
297
|
if (exposed) {
|
|
298
298
|
hostAllowlist.add(`127.0.0.1:${port}`);
|
|
299
299
|
hostAllowlist.add(`localhost:${port}`);
|